<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Yep, it really is a long-standing bug. Script-mode top-level locals are treated as globals (module-scope bindings) by the compiler, but their initial bindings are evaluated eagerly instead of lazily (as you’d want in a script). Taken together, this means that you can get this completely unsafe behavior.</div><div class=""><br class=""></div><div class="">So, why is ‘a’ accepted but ‘b’ not in your original example?</div><div class=""><br class=""></div><blockquote type="cite" class="">func foo() -&gt; Int { return b }<br class="">let a = 1<br class="">let b = 2<br class=""><div class=""><div class="">print(foo())</div></div></blockquote><div class=""></div><div class=""><br class=""></div><div class="">The secret to the current behavior is that script mode is executed interactively, instead of parsing it all up front. To make things a little better, it <i class="">actually</i>&nbsp;parses any number of declarations until it sees something it actually needs to execute—a statement or a declaration with an initial value expression. This allows for recursive functions while still being “live”.</div><div class=""><br class=""></div><div class="">The consequence here is that <i class="">one</i>&nbsp;top-level binding after a series of functions may be visible. This is obviously not optimal.</div><div class=""><br class=""></div><div class="">To fix this, we should:</div><div class=""><br class=""></div><div class="">- Distinguish between script-mode top-level locals and module-scope variables that happen to be declared. My personal preference is to treat anything with explicit access control as a normal lazy global and anything without access as a top-level local.</div><div class=""><br class=""></div><div class="">- Consider parsing everything up front, even if we don’t type-check it, so that we can say “use of ‘b’ before it’s initialized” instead of “undeclared name ‘b’”</div><div class=""><br class=""></div><div class="">Note that we <i class="">do</i>&nbsp;need to be conservative here. This code should continue to be rejected, even though ‘f’ doesn’t refer to ‘local’ directly, because <i class="">calling</i>&nbsp;‘f' would be dangerous before the initialization of ‘local':</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">internal func f() -&gt; Int {</div><div class="">&nbsp; return g()</div><div class="">}</div><div class=""><i class="">// more code here</i></div><div class=""><br class=""></div><div class="">let local = 42</div><div class="">private func g() -&gt; Int {</div><div class="">&nbsp; return local</div><div class="">}</div></blockquote><div class=""><br class=""></div><div class="">Thanks for bringing this up, if only so I have an opportunity to write out the issue. :-)</div><div class="">Jordan</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Sep 21, 2016, at 23:04, Jens Persson &lt;<a href="mailto:jens@bitcycle.com" class="">jens@bitcycle.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Did you see the other code examples that came up in that twitter conversations?<div class="">For example:</div><div class=""><br class=""></div><div class="">This worrying little program compiles:</div><div class=""><div class="">func f() -&gt; Int {</div><div class="">&nbsp; &nbsp; return a</div><div class="">}</div><div class="">let a = f()</div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">It also compiles if you print(a) at the end, and it will print 0.</div><div class=""><br class=""></div><div class="">If we replace Int with [Int] it will still compile but crash when run.</div><div class=""><br class=""></div><div class="">And also this:</div><div class=""><br class=""></div><div class="">AnotherFile.swift containing:</div><div class=""><div class=""><div class="">func f() -&gt; Int {</div><div class="">&nbsp; &nbsp; return a</div><div class="">}</div><div class="">let a = f()</div></div></div><div class=""><br class=""></div><div class="">main.swift containing</div><div class="">print(a)</div><div class=""><br class=""></div><div class="">Compile, run (for eternity, at 0% CPU).</div><div class=""><br class=""></div><div class="">/Jens</div><div class=""><br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Thu, Sep 22, 2016 at 3:13 AM, Joe Groff <span dir="ltr" class="">&lt;<a href="mailto:jgroff@apple.com" target="_blank" class="">jgroff@apple.com</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br class="">
&gt; On Sep 21, 2016, at 2:22 PM, Jens Persson via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; wrote:<br class="">
&gt;<br class="">
</span><div class=""><div class="h5">&gt; // This little Swift program compiles (and runs) fine:<br class="">
&gt;<br class="">
&gt; func foo() -&gt; Int { return a }<br class="">
&gt; let a = 1<br class="">
&gt; let b = 2<br class="">
&gt; print(foo())<br class="">
&gt;<br class="">
&gt; But if `foo()` returns `b` instead of `a`, I get this compile time error:<br class="">
&gt; "Use of unresolved identifier `b`"<br class="">
<br class="">
</div></div>This looks like a bug to me (cc-ing Jordan, who's thought about global scoping issues more than me). In "script mode", it shouldn't be possible to refer to a variable before its initialization is executed. However, the way this is currently modeled is…problematic, to say the least, among other reasons because script globals are still visible to "library" files in the same module.<br class="">
<span class="HOEnZb"><font color="#888888" class=""><br class="">
-Joe</font></span></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></body></html>