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

Jens Persson jens at bitcycle.com
Thu Sep 22 13:23:01 CDT 2016


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()

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/f1b390c6/attachment.html>


More information about the swift-users mailing list