Optional chaining and String properties


(Stephen Schaub) #1

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this
to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.' in
a dotted expression, the rest of the properties evaluate as optional and
are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance,
indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

···

--
Stephen Schaub


(Saagar Jha) #2

Saagar Jha

This isn’t quite how optional chaining in Swift works; see the Swift Programming Guide <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html>, specifically “Linking Multiple Levels of Chaining". Basically, `s?.characters.count` works because `s.characters` isn’t Optional. You only use ? on properties that are Optional.

···

On Aug 1, 2016, at 10:26, Stephen Schaub via swift-users <swift-users@swift.org> wrote:

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.' in a dotted expression, the rest of the properties evaluate as optional and are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance, indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

--
Stephen Schaub
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Stephen Schaub) #3

I understand that the String.characters property is not optional. However,
I am puzzled as to why

s?.characters.count

is legal, but

(s?.characters).count

is not. This seems counterintuitive. Can someone explain the logic or rules
being used here?

Stephen

···

On Mon, Aug 1, 2016 at 2:09 PM, Saagar Jha <saagar@saagarjha.com> wrote:

Saagar Jha

This isn’t quite how optional chaining in Swift works; see the Swift
Programming Guide
<https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html>,
specifically “Linking Multiple Levels of Chaining". Basically,
`s?.characters.count` works because `s.characters` isn’t Optional. You only
use ? on properties that are Optional.

On Aug 1, 2016, at 10:26, Stephen Schaub via swift-users < > swift-users@swift.org> wrote:

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this
to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.'
in a dotted expression, the rest of the properties evaluate as optional and
are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance,
indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

--
Stephen Schaub
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Stephen Schaub


(Jacob Bandes-Storch) #4

You can think of this like flatMap:

    let count = s.flatMap { $0.characters.count } ?? 0 // like
s?.characters.count ?? 0
    let count = s.flatMap { $0.characters }.flatMap { $0.count } ?? 0 //
like (s?.characters)?.count ?? 0

Jacob

···

On Mon, Aug 1, 2016 at 10:26 AM, Stephen Schaub via swift-users < swift-users@swift.org> wrote:

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this
to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.'
in a dotted expression, the rest of the properties evaluate as optional and
are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance,
indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

--
Stephen Schaub

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rimantas Liubertas) #5

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance, indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

See print(s?.characters.count) — you get the optional despite count not being defined as optional
  
Also, try this:

struct Foo {
    let bar: Int
}

var foo: Foo? = Foo(bar: 42)
print(foo?.bar)

Then try this:

struct Foo {
    let bar: Int
    let baz: Int?
}

var foo: Foo? = Foo(bar: 42, baz: 69)
print(foo?.bar)

print(foo?.baz?)

This may give you some ideas.

Best regards,
Rimantas


(Saagar Jha) #6

When you write `(s?.characters).count`, the parentheses are evaluated first; `(s?.characters)` gives an `String.CharacterView?`. Accessing the `String.CharacterView?`’s `count` property requires a `?`: `(s?.characters)?.count`. `s?.characters.count`, on the other hand, is applying chaining, which only gives an Optional at the end, intermediate properties don’t require a `?` unless they’re Optional themselves.

Saagar Jha

···

On Aug 1, 2016, at 11:17, Stephen Schaub <sschaub@gmail.com> wrote:

I understand that the String.characters property is not optional. However, I am puzzled as to why

s?.characters.count

is legal, but

(s?.characters).count

is not. This seems counterintuitive. Can someone explain the logic or rules being used here?

Stephen

On Mon, Aug 1, 2016 at 2:09 PM, Saagar Jha <saagar@saagarjha.com <mailto:saagar@saagarjha.com>> wrote:

Saagar Jha

This isn’t quite how optional chaining in Swift works; see the Swift Programming Guide <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html>, specifically “Linking Multiple Levels of Chaining". Basically, `s?.characters.count` works because `s.characters` isn’t Optional. You only use ? on properties that are Optional.

On Aug 1, 2016, at 10:26, Stephen Schaub via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.' in a dotted expression, the rest of the properties evaluate as optional and are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance, indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

--
Stephen Schaub
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

--
Stephen Schaub


(Stephen Schaub) #7

Got it, I think! I didn't understand that the chaining of intermediate
properties worked that way.

Thanks very much for the explanation.

Stephen

···

On Mon, Aug 1, 2016 at 2:25 PM, Saagar Jha <saagar@saagarjha.com> wrote:

When you write `(s?.characters).count`, the parentheses are evaluated
first; `(s?.characters)` gives an `String.CharacterView?`. Accessing
the `String.CharacterView?`’s `count` property requires a
`?`: `(s?.characters)?.count`. `s?.characters.count`, on the other hand, is
applying chaining, which only gives an Optional at the end, intermediate
properties don’t require a `?` unless they’re Optional themselves.

Saagar Jha

On Aug 1, 2016, at 11:17, Stephen Schaub <sschaub@gmail.com> wrote:

I understand that the String.characters property is not optional. However,
I am puzzled as to why

s?.characters.count

is legal, but

(s?.characters).count

is not. This seems counterintuitive. Can someone explain the logic or
rules being used here?

Stephen

On Mon, Aug 1, 2016 at 2:09 PM, Saagar Jha <saagar@saagarjha.com> wrote:

Saagar Jha

This isn’t quite how optional chaining in Swift works; see the Swift
Programming Guide
<https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html>,
specifically “Linking Multiple Levels of Chaining". Basically,
`s?.characters.count` works because `s.characters` isn’t Optional. You only
use ? on properties that are Optional.

On Aug 1, 2016, at 10:26, Stephen Schaub via swift-users < >> swift-users@swift.org> wrote:

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this
to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.'
in a dotted expression, the rest of the properties evaluate as optional and
are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance,
indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

--
Stephen Schaub
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Stephen Schaub

--
Stephen Schaub


(Jacob Bandes-Storch) #8

er, I guess it's probably plain ol' map, rather than flatMap.

···

On Mon, Aug 1, 2016 at 8:28 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

You can think of this like flatMap:

    let count = s.flatMap { $0.characters.count } ?? 0 // like
s?.characters.count ?? 0
    let count = s.flatMap { $0.characters }.flatMap { $0.count } ?? 0 //
like (s?.characters)?.count ?? 0

Jacob

On Mon, Aug 1, 2016 at 10:26 AM, Stephen Schaub via swift-users < > swift-users@swift.org> wrote:

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this
to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.'
in a dotted expression, the rest of the properties evaluate as optional and
are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance,
indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

--
Stephen Schaub

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


#9

If you are looking for the actual rules, they are defined in the
language reference, in the section on optional chaining expressions
[1]. It states that if you have an optional chaining expression of the
form `expression?` then

"If the value of the optional-chaining expression is nil, all of the
other operations in the postfix expression are ignored and the entire
postfix expression evaluates to nil. If the value of the
optional-chaining expression is not nil, the value of the
optional-chaining expression is unwrapped and used to evaluate the
rest of the postfix expression. [...]. If a postfix expression that
contains an optional-chaining expression is nested inside other
postfix expressions, only the outermost expression returns an optional
type."

However, it seems to me that this is not quite a correct description
of what swiftc does. Note the last sentence in particular. According
to the grammar, given a postfix expression <e> and two identifiers x
and y, the following are both postfix expressions:

<e>?.x.y
(<e>?.x).y

Without further specification, I would consider "the outermost
expression" to be `(<e>?.x).y` for the last case, when swiftc clearly
stops at parentheses. The spec should distinguish between
parenthesized-expressions and other postfix expressions or am I
missing that part?

[1] https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/optional-chaining-expression

···

On Mon, Aug 1, 2016 at 8:17 PM, Stephen Schaub via swift-users <swift-users@swift.org> wrote:

I understand that the String.characters property is not optional. However, I
am puzzled as to why

s?.characters.count

is legal, but

(s?.characters).count

is not. This seems counterintuitive. Can someone explain the logic or rules
being used here?

Stephen

On Mon, Aug 1, 2016 at 2:09 PM, Saagar Jha <saagar@saagarjha.com> wrote:

Saagar Jha

This isn’t quite how optional chaining in Swift works; see the Swift
Programming Guide, specifically “Linking Multiple Levels of Chaining".
Basically, `s?.characters.count` works because `s.characters` isn’t
Optional. You only use ? on properties that are Optional.

On Aug 1, 2016, at 10:26, Stephen Schaub via swift-users >> <swift-users@swift.org> wrote:

With optional chaining, if I have a Swift variable

    var s: String?

s might contain nil, or a String wrapped in an Optional. So, I tried this
to get its length:

    let count = s?.characters?.count ?? 0

However, the compiler wants this:

    let count = s?.characters.count ?? 0

or this:

    let count = (s?.characters)?.count ?? 0

My understanding of optional chaining is that, once you start using '?.'
in a dotted expression, the rest of the properties evaluate as optional and
are typically accessed by '?.', not '.'.

So, I dug a little further and tried this in the playground:

var s: String? = "Foo"
print(s?.characters)

The result indicates that s?.characters is indeed an Optional instance,
indicating that s?.characters.count should be illegal.

Why is s?.characters.count a legal expression?

--
Stephen Schaub
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Stephen Schaub

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Stephen Schaub) #10

Ingo,

Thanks for pointing me to the specification. The example given in that
section is helpful.

You make a good point about what constitutes "the outermost expression."
Parenthesized expressions, according to the spec, are primary expressions,
not postfix expressions, but the spec also states that "Syntactically,
every primary expression is also a postfix expression." So, either I'm not
understanding the spec correctly, or the compiler is handling this case
differently for some reason.

Stephen

···

On Mon, Aug 1, 2016 at 3:05 PM, Ingo Maier <ingoem@gmail.com> wrote:

If you are looking for the actual rules, they are defined in the
language reference, in the section on optional chaining expressions
[1]. It states that if you have an optional chaining expression of the
form `expression?` then

"If the value of the optional-chaining expression is nil, all of the
other operations in the postfix expression are ignored and the entire
postfix expression evaluates to nil. If the value of the
optional-chaining expression is not nil, the value of the
optional-chaining expression is unwrapped and used to evaluate the
rest of the postfix expression. [...]. If a postfix expression that
contains an optional-chaining expression is nested inside other
postfix expressions, only the outermost expression returns an optional
type."

However, it seems to me that this is not quite a correct description
of what swiftc does. Note the last sentence in particular. According
to the grammar, given a postfix expression <e> and two identifiers x
and y, the following are both postfix expressions:

<e>?.x.y
(<e>?.x).y

Without further specification, I would consider "the outermost
expression" to be `(<e>?.x).y` for the last case, when swiftc clearly
stops at parentheses. The spec should distinguish between
parenthesized-expressions and other postfix expressions or am I
missing that part?

[1]
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/optional-chaining-expression

On Mon, Aug 1, 2016 at 8:17 PM, Stephen Schaub via swift-users > <swift-users@swift.org> wrote:
> I understand that the String.characters property is not optional.
However, I
> am puzzled as to why
>
> s?.characters.count
>
> is legal, but
>
> (s?.characters).count
>
> is not. This seems counterintuitive. Can someone explain the logic or
rules
> being used here?
>
> Stephen
>
>
>
>
> On Mon, Aug 1, 2016 at 2:09 PM, Saagar Jha <saagar@saagarjha.com> wrote:
>>
>>
>> Saagar Jha
>>
>> This isn’t quite how optional chaining in Swift works; see the Swift
>> Programming Guide, specifically “Linking Multiple Levels of Chaining".
>> Basically, `s?.characters.count` works because `s.characters` isn’t
>> Optional. You only use ? on properties that are Optional.
>>
>> On Aug 1, 2016, at 10:26, Stephen Schaub via swift-users > >> <swift-users@swift.org> wrote:
>>
>> With optional chaining, if I have a Swift variable
>>
>> var s: String?
>>
>> s might contain nil, or a String wrapped in an Optional. So, I tried
this
>> to get its length:
>>
>> let count = s?.characters?.count ?? 0
>>
>> However, the compiler wants this:
>>
>> let count = s?.characters.count ?? 0
>>
>> or this:
>>
>> let count = (s?.characters)?.count ?? 0
>>
>> My understanding of optional chaining is that, once you start using '?.'
>> in a dotted expression, the rest of the properties evaluate as optional
and
>> are typically accessed by '?.', not '.'.
>>
>> So, I dug a little further and tried this in the playground:
>>
>> var s: String? = "Foo"
>> print(s?.characters)
>>
>> The result indicates that s?.characters is indeed an Optional instance,
>> indicating that s?.characters.count should be illegal.
>>
>> Why is s?.characters.count a legal expression?
>>
>>
>> --
>> Stephen Schaub
>> _______________________________________________
>> swift-users mailing list
>> swift-users@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>>
>
>
>
> --
> Stephen Schaub
>
> _______________________________________________
> swift-users mailing list
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>

--
Stephen Schaub


#11

Yes, parenthesized expressions are primary expressions, which in turn
are all postfix expressions as specified by the first grammar rule for
postfix expressions and also the note you mentioned. I do think that
swiftc's behavior is the most intuitive. I just think the spec needs
to be clarified in that regard, that's all.

Cheers,
Ingo

···

On Mon, Aug 1, 2016 at 9:24 PM, Stephen Schaub <sschaub@gmail.com> wrote:

Ingo,

Thanks for pointing me to the specification. The example given in that
section is helpful.

You make a good point about what constitutes "the outermost expression."
Parenthesized expressions, according to the spec, are primary expressions,
not postfix expressions, but the spec also states that "Syntactically, every
primary expression is also a postfix expression." So, either I'm not
understanding the spec correctly, or the compiler is handling this case
differently for some reason.

Stephen

On Mon, Aug 1, 2016 at 3:05 PM, Ingo Maier <ingoem@gmail.com> wrote:

If you are looking for the actual rules, they are defined in the
language reference, in the section on optional chaining expressions
[1]. It states that if you have an optional chaining expression of the
form `expression?` then

"If the value of the optional-chaining expression is nil, all of the
other operations in the postfix expression are ignored and the entire
postfix expression evaluates to nil. If the value of the
optional-chaining expression is not nil, the value of the
optional-chaining expression is unwrapped and used to evaluate the
rest of the postfix expression. [...]. If a postfix expression that
contains an optional-chaining expression is nested inside other
postfix expressions, only the outermost expression returns an optional
type."

However, it seems to me that this is not quite a correct description
of what swiftc does. Note the last sentence in particular. According
to the grammar, given a postfix expression <e> and two identifiers x
and y, the following are both postfix expressions:

<e>?.x.y
(<e>?.x).y

Without further specification, I would consider "the outermost
expression" to be `(<e>?.x).y` for the last case, when swiftc clearly
stops at parentheses. The spec should distinguish between
parenthesized-expressions and other postfix expressions or am I
missing that part?

[1]
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/optional-chaining-expression

On Mon, Aug 1, 2016 at 8:17 PM, Stephen Schaub via swift-users >> <swift-users@swift.org> wrote:
> I understand that the String.characters property is not optional.
> However, I
> am puzzled as to why
>
> s?.characters.count
>
> is legal, but
>
> (s?.characters).count
>
> is not. This seems counterintuitive. Can someone explain the logic or
> rules
> being used here?
>
> Stephen
>
>
>
>
> On Mon, Aug 1, 2016 at 2:09 PM, Saagar Jha <saagar@saagarjha.com> wrote:
>>
>>
>> Saagar Jha
>>
>> This isn’t quite how optional chaining in Swift works; see the Swift
>> Programming Guide, specifically “Linking Multiple Levels of Chaining".
>> Basically, `s?.characters.count` works because `s.characters` isn’t
>> Optional. You only use ? on properties that are Optional.
>>
>> On Aug 1, 2016, at 10:26, Stephen Schaub via swift-users >> >> <swift-users@swift.org> wrote:
>>
>> With optional chaining, if I have a Swift variable
>>
>> var s: String?
>>
>> s might contain nil, or a String wrapped in an Optional. So, I tried
>> this
>> to get its length:
>>
>> let count = s?.characters?.count ?? 0
>>
>> However, the compiler wants this:
>>
>> let count = s?.characters.count ?? 0
>>
>> or this:
>>
>> let count = (s?.characters)?.count ?? 0
>>
>> My understanding of optional chaining is that, once you start using
>> '?.'
>> in a dotted expression, the rest of the properties evaluate as optional
>> and
>> are typically accessed by '?.', not '.'.
>>
>> So, I dug a little further and tried this in the playground:
>>
>> var s: String? = "Foo"
>> print(s?.characters)
>>
>> The result indicates that s?.characters is indeed an Optional instance,
>> indicating that s?.characters.count should be illegal.
>>
>> Why is s?.characters.count a legal expression?
>>
>>
>> --
>> Stephen Schaub
>> _______________________________________________
>> swift-users mailing list
>> swift-users@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>>
>
>
>
> --
> Stephen Schaub
>
> _______________________________________________
> swift-users mailing list
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>

--
Stephen Schaub