<div dir="ltr">Ah, yes. Thanks.</div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 22, 2016 at 8:29 PM, 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 class=""><br>
&gt; On Sep 22, 2016, at 11:28 AM, Jens Persson &lt;<a href="mailto:jens@bitcycle.com">jens@bitcycle.com</a>&gt; wrote:<br>
&gt;<br>
&gt; Yes, but should the compiler silently accept that? And is this issue really related to the other issue?<br>
<br>
</span>No, this is a separate issue. The compiler might be able to catch some obvious cases, but it&#39;d be impossible to statically prevent all circularities. The runtime could probably do a better job detecting this situation, though, and give a runtime error instead of just letting the deadlock happen.<br>
<span class="HOEnZb"><font color="#888888"><br>
-Joe<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
&gt; /Jens<br>
&gt;<br>
&gt; On Thu, Sep 22, 2016 at 8:23 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com">jgroff@apple.com</a>&gt; wrote:<br>
&gt;<br>
&gt; &gt; On Sep 22, 2016, at 11:23 AM, Jens Persson &lt;<a href="mailto:jens@bitcycle.com">jens@bitcycle.com</a>&gt; wrote:<br>
&gt; &gt;<br>
&gt; &gt; Oh, but how can the following (earlier mentioned) example have anything to do with Script-mode top-level locals being treated as globals?<br>
&gt; &gt;<br>
&gt; &gt; Create &quot;AnotherFile.swift&quot; containing:<br>
&gt; &gt; func f() -&gt; Int { return a }<br>
&gt; &gt; let a = f()<br>
&gt;<br>
&gt; In this case, you have a deadlock, since the initialization of `a` depends on its own initialization.<br>
&gt;<br>
&gt; -Joe<br>
&gt;<br>
&gt; &gt; Create &quot;main.swift&quot; containing:<br>
&gt; &gt; print(a)<br>
&gt; &gt;<br>
&gt; &gt; Compile. Run. For ever. At zero % CPU.<br>
&gt; &gt;<br>
&gt; &gt; /Jens<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt; On Thu, Sep 22, 2016 at 8:03 PM, Jens Persson &lt;<a href="mailto:jens@bitcycle.com">jens@bitcycle.com</a>&gt; wrote:<br>
&gt; &gt; Thank you for the thorough explanation!<br>
&gt; &gt; /Jens<br>
&gt; &gt;<br>
&gt; &gt; On Thu, Sep 22, 2016 at 7:28 PM, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com">jordan_rose@apple.com</a>&gt; wrote:<br>
&gt; &gt; 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.<br>
&gt; &gt;<br>
&gt; &gt; So, why is ‘a’ accepted but ‘b’ not in your original example?<br>
&gt; &gt;<br>
&gt; &gt;&gt; func foo() -&gt; Int { return b }<br>
&gt; &gt;&gt; let a = 1<br>
&gt; &gt;&gt; let b = 2<br>
&gt; &gt;&gt; print(foo())<br>
&gt; &gt;<br>
&gt; &gt; 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 actually 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”.<br>
&gt; &gt;<br>
&gt; &gt; The consequence here is that one top-level binding after a series of functions may be visible. This is obviously not optimal.<br>
&gt; &gt;<br>
&gt; &gt; To fix this, we should:<br>
&gt; &gt;<br>
&gt; &gt; - 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.<br>
&gt; &gt;<br>
&gt; &gt; - 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’”<br>
&gt; &gt;<br>
&gt; &gt; Note that we do need to be conservative here. This code should continue to be rejected, even though ‘f’ doesn’t refer to ‘local’ directly, because calling ‘f&#39; would be dangerous before the initialization of ‘local&#39;:<br>
&gt; &gt;<br>
&gt; &gt; internal func f() -&gt; Int {<br>
&gt; &gt;   return g()<br>
&gt; &gt; }<br>
&gt; &gt; // more code here<br>
&gt; &gt;<br>
&gt; &gt; let local = 42<br>
&gt; &gt; private func g() -&gt; Int {<br>
&gt; &gt;   return local<br>
&gt; &gt; }<br>
&gt; &gt;<br>
&gt; &gt; Thanks for bringing this up, if only so I have an opportunity to write out the issue. :-)<br>
&gt; &gt; Jordan<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt;&gt; On Sep 21, 2016, at 23:04, Jens Persson &lt;<a href="mailto:jens@bitcycle.com">jens@bitcycle.com</a>&gt; wrote:<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; Did you see the other code examples that came up in that twitter conversations?<br>
&gt; &gt;&gt; For example:<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; This worrying little program compiles:<br>
&gt; &gt;&gt; func f() -&gt; Int {<br>
&gt; &gt;&gt;     return a<br>
&gt; &gt;&gt; }<br>
&gt; &gt;&gt; let a = f()<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; It also compiles if you print(a) at the end, and it will print 0.<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; If we replace Int with [Int] it will still compile but crash when run.<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; And also this:<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; AnotherFile.swift containing:<br>
&gt; &gt;&gt; func f() -&gt; Int {<br>
&gt; &gt;&gt;     return a<br>
&gt; &gt;&gt; }<br>
&gt; &gt;&gt; let a = f()<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; main.swift containing<br>
&gt; &gt;&gt; print(a)<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; Compile, run (for eternity, at 0% CPU).<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; /Jens<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; On Thu, Sep 22, 2016 at 3:13 AM, Joe Groff &lt;<a href="mailto:jgroff@apple.com">jgroff@apple.com</a>&gt; wrote:<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; &gt; On Sep 21, 2016, at 2:22 PM, Jens Persson via swift-users &lt;<a href="mailto:swift-users@swift.org">swift-users@swift.org</a>&gt; wrote:<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; // This little Swift program compiles (and runs) fine:<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; func foo() -&gt; Int { return a }<br>
&gt; &gt;&gt; &gt; let a = 1<br>
&gt; &gt;&gt; &gt; let b = 2<br>
&gt; &gt;&gt; &gt; print(foo())<br>
&gt; &gt;&gt; &gt;<br>
&gt; &gt;&gt; &gt; But if `foo()` returns `b` instead of `a`, I get this compile time error:<br>
&gt; &gt;&gt; &gt; &quot;Use of unresolved identifier `b`&quot;<br>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; 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>
&gt; &gt;&gt;<br>
&gt; &gt;&gt; -Joe<br>
&gt; &gt;&gt;<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt;<br>
&gt;<br>
<br>
</div></div></blockquote></div><br></div>