<div dir="ltr">Oh, but how can the following (earlier mentioned) example have anything to do with Script-mode top-level locals being treated as globals?<div><br></div><div><div>Create &quot;AnotherFile.swift&quot; containing:</div><div>func f() -&gt; Int { return a }<br></div><div>let a = f()</div><div><br></div><div>Create &quot;main.swift&quot; containing:</div><div>print(a)<br></div><div><br></div><div>Compile. Run. For ever. At zero % CPU.</div></div><div><br></div><div>/Jens</div><div><br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 22, 2016 at 8:03 PM, Jens Persson <span dir="ltr">&lt;<a href="mailto:jens@bitcycle.com" target="_blank">jens@bitcycle.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Thank you for the <span style="color:rgb(50,50,50);font-family:arial,&#39;lucida grande&#39;,helvetica,tahoma,verdana,sans-serif;font-size:14.399999618530273px;background-color:rgb(255,255,250)">thorough explanation!</span><span class="HOEnZb"><font color="#888888"><div>/Jens</div></font></span></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 22, 2016 at 7:28 PM, Jordan Rose <span dir="ltr">&lt;<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>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><br></div><div>So, why is ‘a’ accepted but ‘b’ not in your original example?</div><div><br></div><blockquote type="cite">func foo() -&gt; Int { return b }<span><br>let a = 1<br>let b = 2<br><div><div>print(foo())</div></div></span></blockquote><div></div><div><br></div><div>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>actually</i> 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><br></div><div>The consequence here is that <i>one</i> top-level binding after a series of functions may be visible. This is obviously not optimal.</div><div><br></div><div>To fix this, we should:</div><div><br></div><div>- 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><br></div><div>- 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><br></div><div>Note that we <i>do</i> need to be conservative here. This code should continue to be rejected, even though ‘f’ doesn’t refer to ‘local’ directly, because <i>calling</i> ‘f&#39; would be dangerous before the initialization of ‘local&#39;:</div><div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div>internal func f() -&gt; Int {</div><div>  return g()</div><div>}</div><div><i>// more code here</i></div><div><br></div><div>let local = 42</div><div>private func g() -&gt; Int {</div><div>  return local</div><div>}</div></blockquote><div><br></div><div>Thanks for bringing this up, if only so I have an opportunity to write out the issue. :-)</div><span><font color="#888888"><div>Jordan</div></font></span><div><div><div><br></div><br><div><blockquote type="cite"><div>On Sep 21, 2016, at 23:04, Jens Persson &lt;<a href="mailto:jens@bitcycle.com" target="_blank">jens@bitcycle.com</a>&gt; wrote:</div><br><div><div dir="ltr">Did you see the other code examples that came up in that twitter conversations?<div>For example:</div><div><br></div><div>This worrying little program compiles:</div><div><div>func f() -&gt; Int {</div><div>    return a</div><div>}</div><div>let a = f()</div></div><div><br></div><div><br></div><div>It also compiles if you print(a) at the end, and it will print 0.</div><div><br></div><div>If we replace Int with [Int] it will still compile but crash when run.</div><div><br></div><div>And also this:</div><div><br></div><div>AnotherFile.swift containing:</div><div><div><div>func f() -&gt; Int {</div><div>    return a</div><div>}</div><div>let a = f()</div></div></div><div><br></div><div>main.swift containing</div><div>print(a)</div><div><br></div><div>Compile, run (for eternity, at 0% CPU).</div><div><br></div><div>/Jens</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 22, 2016 at 3:13 AM, Joe Groff <span dir="ltr">&lt;<a href="mailto:jgroff@apple.com" target="_blank">jgroff@apple.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span><br>
&gt; On Sep 21, 2016, at 2:22 PM, Jens Persson via swift-users &lt;<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>&gt; wrote:<br>
&gt;<br>
</span><div><div>&gt; // This little Swift program compiles (and runs) fine:<br>
&gt;<br>
&gt; func foo() -&gt; Int { return a }<br>
&gt; let a = 1<br>
&gt; let b = 2<br>
&gt; print(foo())<br>
&gt;<br>
&gt; But if `foo()` returns `b` instead of `a`, I get this compile time error:<br>
&gt; &quot;Use of unresolved identifier `b`&quot;<br>
<br>
</div></div>This looks like a bug to me (cc-ing Jordan, who&#39;s thought about global scoping issues more than me). In &quot;script mode&quot;, it shouldn&#39;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 &quot;library&quot; files in the same module.<br>
<span><font color="#888888"><br>
-Joe</font></span></blockquote></div><br></div>
</div></blockquote></div><br></div></div></div></blockquote></div><br></div>
</div></div></blockquote></div><br></div>