[swift-users] Can anyone please explain this behavior?

Jens Persson jens at bitcycle.com
Thu Sep 22 13:34:33 CDT 2016


Ah, yes. Thanks.

On Thu, Sep 22, 2016 at 8:29 PM, Joe Groff <jgroff at apple.com> wrote:

>
> > On Sep 22, 2016, at 11:28 AM, Jens Persson <jens at bitcycle.com> wrote:
> >
> > Yes, but should the compiler silently accept that? And is this issue
> really related to the other issue?
>
> No, this is a separate issue. The compiler might be able to catch some
> obvious cases, but it'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.
>
> -Joe
>
> > /Jens
> >
> > On Thu, Sep 22, 2016 at 8:23 PM, Joe Groff <jgroff at apple.com> wrote:
> >
> > > On Sep 22, 2016, at 11:23 AM, Jens Persson <jens at bitcycle.com> wrote:
> > >
> > > Oh, but how can the following (earlier mentioned) example have
> anything to do with Script-mode top-level locals being treated as globals?
> > >
> > > Create "AnotherFile.swift" containing:
> > > func f() -> Int { return a }
> > > let a = f()
> >
> > In this case, you have a deadlock, since the initialization of `a`
> depends on its own initialization.
> >
> > -Joe
> >
> > > Create "main.swift" containing:
> > > print(a)
> > >
> > > Compile. Run. For ever. At zero % CPU.
> > >
> > > /Jens
> > >
> > >
> > >
> > > On Thu, Sep 22, 2016 at 8:03 PM, Jens Persson <jens at bitcycle.com>
> wrote:
> > > Thank you for the thorough explanation!
> > > /Jens
> > >
> > > On Thu, Sep 22, 2016 at 7:28 PM, Jordan Rose <jordan_rose at apple.com>
> wrote:
> > > 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.
> > >
> > > So, why is ‘a’ accepted but ‘b’ not in your original example?
> > >
> > >> func foo() -> Int { return b }
> > >> let a = 1
> > >> let b = 2
> > >> print(foo())
> > >
> > > 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”.
> > >
> > > The consequence here is that one top-level binding after a series of
> functions may be visible. This is obviously not optimal.
> > >
> > > To fix this, we should:
> > >
> > > - 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.
> > >
> > > - 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’”
> > >
> > > 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' would be dangerous before the initialization of ‘local':
> > >
> > > internal func f() -> Int {
> > >   return g()
> > > }
> > > // more code here
> > >
> > > let local = 42
> > > private func g() -> Int {
> > >   return local
> > > }
> > >
> > > Thanks for bringing this up, if only so I have an opportunity to write
> out the issue. :-)
> > > Jordan
> > >
> > >
> > >> On Sep 21, 2016, at 23:04, Jens Persson <jens at bitcycle.com> wrote:
> > >>
> > >> Did you see the other code examples that came up in that twitter
> conversations?
> > >> For example:
> > >>
> > >> This worrying little program compiles:
> > >> func f() -> Int {
> > >>     return a
> > >> }
> > >> let a = f()
> > >>
> > >>
> > >> It also compiles if you print(a) at the end, and it will print 0.
> > >>
> > >> If we replace Int with [Int] it will still compile but crash when run.
> > >>
> > >> And also this:
> > >>
> > >> AnotherFile.swift containing:
> > >> func f() -> Int {
> > >>     return a
> > >> }
> > >> let a = f()
> > >>
> > >> main.swift containing
> > >> print(a)
> > >>
> > >> Compile, run (for eternity, at 0% CPU).
> > >>
> > >> /Jens
> > >>
> > >>
> > >> On Thu, Sep 22, 2016 at 3:13 AM, Joe Groff <jgroff at apple.com> wrote:
> > >>
> > >> > On Sep 21, 2016, at 2:22 PM, Jens Persson via swift-users <
> swift-users at swift.org> wrote:
> > >> >
> > >> > // This little Swift program compiles (and runs) fine:
> > >> >
> > >> > func foo() -> Int { return a }
> > >> > let a = 1
> > >> > let b = 2
> > >> > print(foo())
> > >> >
> > >> > But if `foo()` returns `b` instead of `a`, I get this compile time
> error:
> > >> > "Use of unresolved identifier `b`"
> > >>
> > >> 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.
> > >>
> > >> -Joe
> > >>
> > >
> > >
> > >
> >
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160922/d1f806cc/attachment.html>


More information about the swift-users mailing list