mandatory "?" suffix for identifiers associated with optional types


(Amir Michail) #1

So for example the following (probable) bug would result in a compile error:

let f = x < 5 // where x is optional and could be nil

If that was really what was intended, you would need to write:

let f = x? < 5

Similarly, the rule would also apply for functions that return an optional type:

let f = x()? < 5

A major advantage of this approach is it would encourage programmers to unwrap optionals early to avoid writing “?” and “?!" frequently in their code.

Note that conditional chaining would just make use of the existing “?” suffix. There is no need to add another “?” after that.

let f = x?.g?.h
let f = x()?.g?.h

As for implicitly unwrapped optionals, a “?” suffix would only be used when you want to treat a value as an optional (e.g., when comparing it to nil). For example, for x of type Int?, one could write:

let y = (x? == nil) ? 0 : x


(Chéyo Jiménez) #2

This a little confusing, I don't think adding yet another question mark
helps. The ?? ( nil coalescing operator) already included in swift handles
checking for nil values. If anything, the ternary operator just makes
matters worse in this example. If else would be better imo.

https://lists.swift.org/pipermail/swift-evolution/2015-December/000133.html

···

On Friday, December 4, 2015, Amir Michail <a.michail@me.com> wrote:

So for example the following (probable) bug would result in a compile
error:

let f = x < 5 // where x is optional and could be nil

If that was really what was intended, you would need to write:

let f = x? < 5

Similarly, the rule would also apply for functions that return an optional
type:

let f = x()? < 5

A major advantage of this approach is it would encourage programmers to
unwrap optionals early to avoid writing “?” and “?!" frequently in their
code.

Note that conditional chaining would just make use of the existing “?”
suffix. There is no need to add another “?” after that.

let f = x?.g?.h
let f = x()?.g?.h

As for implicitly unwrapped optionals, a “?” suffix would only be used
when you want to treat a value as an optional (e.g., when comparing it to
nil). For example, for x of type Int?, one could write:

let y = (x? == nil) ? 0 : x

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Amir Michail) #3

This a little confusing, I don't think adding yet another question mark helps. The ?? ( nil coalescing operator) already included in swift handles checking for nil values. If anything, the ternary operator just makes matters worse in this example. If else would be better imo.

https://lists.swift.org/pipermail/swift-evolution/2015-December/000133.html

I don’t want to remember if a variable is optional. I want to see it in the variable name.

···

On Dec 4, 2015, at 10:41 AM, J. Cheyo Jimenez <cheyo@masters3d.com> wrote:

On Friday, December 4, 2015, Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> wrote:
So for example the following (probable) bug would result in a compile error:

let f = x < 5 // where x is optional and could be nil

If that was really what was intended, you would need to write:

let f = x? < 5

Similarly, the rule would also apply for functions that return an optional type:

let f = x()? < 5

A major advantage of this approach is it would encourage programmers to unwrap optionals early to avoid writing “?” and “?!" frequently in their code.

Note that conditional chaining would just make use of the existing “?” suffix. There is no need to add another “?” after that.

let f = x?.g?.h
let f = x()?.g?.h

As for implicitly unwrapped optionals, a “?” suffix would only be used when you want to treat a value as an optional (e.g., when comparing it to nil). For example, for x of type Int?, one could write:

let y = (x? == nil) ? 0 : x

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #4

I don’t think this approach can work.

Consider the == operator for example: if optionals are are equatable then they will work with ==. If they are not, they cannot be used as a dictionary key. The former approach defeats your goals, the later approach defeats common problems from being solved.

-Chris

···

On Dec 4, 2015, at 7:20 AM, Amir Michail <a.michail@me.com> wrote:

So for example the following (probable) bug would result in a compile error:

let f = x < 5 // where x is optional and could be nil

If that was really what was intended, you would need to write:

let f = x? < 5


(David Waite) #5

Ruby recently ran into a similar problem from the other direction - they wanted to support ?. syntax, but ‘?’ was already legal in identifier names (and used) to represent result values which are meant to be considered ‘truthy’. In the end, they went with a different “&." syntax because
1. This meant ‘?’ was both a naming convention and an operation
2. Too many question marks made the code psychologically confusing
3. They already had to change the syntax (to ‘.?’) to make code unambiguous

An naming system or pattern indicating something optional isn’t a bad idea - but it probably shouldn’t use ‘?’ for the same reason. A ‘?’ is already used heavily to indicate actions against optionals, and every time you see that identifier you will have to think about whether you are just referencing it by name, or performing some operation on it.

I think you however are pushing for a mandatory naming system for optionals - to make it clear in your examples below that ‘x’ needs to be treated as an optional, not as the type contained within. This makes coming up with an acceptable system significantly harder.

-DW

···

On Dec 4, 2015, at 8:44 AM, Amir Michail <a.michail@me.com> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.

On Friday, December 4, 2015, Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> wrote:
So for example the following (probable) bug would result in a compile error:

let f = x < 5 // where x is optional and could be nil

If that was really what was intended, you would need to write:

let f = x? < 5

Similarly, the rule would also apply for functions that return an optional type:

let f = x()? < 5

A major advantage of this approach is it would encourage programmers to unwrap optionals early to avoid writing “?” and “?!" frequently in their code.

Note that conditional chaining would just make use of the existing “?” suffix. There is no need to add another “?” after that.

let f = x?.g?.h
let f = x()?.g?.h

As for implicitly unwrapped optionals, a “?” suffix would only be used when you want to treat a value as an optional (e.g., when comparing it to nil). For example, for x of type Int?, one could write:

let y = (x? == nil) ? 0 : x

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Sean Heber) #6

Couldn’t this issue of remembering which variables are optional be solved in the IDE by using a different color for optionals or something like that?

l8r
Sean

···

On Dec 4, 2015, at 9:56 AM, David Waite <david@alkaline-solutions.com> wrote:

Ruby recently ran into a similar problem from the other direction - they wanted to support ?. syntax, but ‘?’ was already legal in identifier names (and used) to represent result values which are meant to be considered ‘truthy’. In the end, they went with a different “&." syntax because
1. This meant ‘?’ was both a naming convention and an operation
2. Too many question marks made the code psychologically confusing
3. They already had to change the syntax (to ‘.?’) to make code unambiguous

An naming system or pattern indicating something optional isn’t a bad idea - but it probably shouldn’t use ‘?’ for the same reason. A ‘?’ is already used heavily to indicate actions against optionals, and every time you see that identifier you will have to think about whether you are just referencing it by name, or performing some operation on it.

I think you however are pushing for a mandatory naming system for optionals - to make it clear in your examples below that ‘x’ needs to be treated as an optional, not as the type contained within. This makes coming up with an acceptable system significantly harder.

-DW

On Dec 4, 2015, at 8:44 AM, Amir Michail <a.michail@me.com> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.

On Friday, December 4, 2015, Amir Michail <a.michail@me.com> wrote:
So for example the following (probable) bug would result in a compile error:

let f = x < 5 // where x is optional and could be nil

If that was really what was intended, you would need to write:

let f = x? < 5

Similarly, the rule would also apply for functions that return an optional type:

let f = x()? < 5

A major advantage of this approach is it would encourage programmers to unwrap optionals early to avoid writing “?” and “?!" frequently in their code.

Note that conditional chaining would just make use of the existing “?” suffix. There is no need to add another “?” after that.

let f = x?.g?.h
let f = x()?.g?.h

As for implicitly unwrapped optionals, a “?” suffix would only be used when you want to treat a value as an optional (e.g., when comparing it to nil). For example, for x of type Int?, one could write:

let y = (x? == nil) ? 0 : x

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

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


(Amir Michail) #7

Couldn’t this issue of remembering which variables are optional be solved in the IDE by using a different color for optionals or something like that?

It’s better in the language because it forces the programmer to think more about what they are doing and the compiler could generate more errors for possible bugs.

Also, the syntax highlighting you propose would not be supported in all contexts (e.g., email, mailing lists, github, etc.).

···

On Dec 4, 2015, at 11:01 AM, Sean Heber <sean@fifthace.com> wrote:

l8r
Sean

On Dec 4, 2015, at 9:56 AM, David Waite <david@alkaline-solutions.com> wrote:

Ruby recently ran into a similar problem from the other direction - they wanted to support ?. syntax, but ‘?’ was already legal in identifier names (and used) to represent result values which are meant to be considered ‘truthy’. In the end, they went with a different “&." syntax because
1. This meant ‘?’ was both a naming convention and an operation
2. Too many question marks made the code psychologically confusing
3. They already had to change the syntax (to ‘.?’) to make code unambiguous

An naming system or pattern indicating something optional isn’t a bad idea - but it probably shouldn’t use ‘?’ for the same reason. A ‘?’ is already used heavily to indicate actions against optionals, and every time you see that identifier you will have to think about whether you are just referencing it by name, or performing some operation on it.

I think you however are pushing for a mandatory naming system for optionals - to make it clear in your examples below that ‘x’ needs to be treated as an optional, not as the type contained within. This makes coming up with an acceptable system significantly harder.

-DW

On Dec 4, 2015, at 8:44 AM, Amir Michail <a.michail@me.com> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.

On Friday, December 4, 2015, Amir Michail <a.michail@me.com> wrote:
So for example the following (probable) bug would result in a compile error:

let f = x < 5 // where x is optional and could be nil

If that was really what was intended, you would need to write:

let f = x? < 5

Similarly, the rule would also apply for functions that return an optional type:

let f = x()? < 5

A major advantage of this approach is it would encourage programmers to unwrap optionals early to avoid writing “?” and “?!" frequently in their code.

Note that conditional chaining would just make use of the existing “?” suffix. There is no need to add another “?” after that.

let f = x?.g?.h
let f = x()?.g?.h

As for implicitly unwrapped optionals, a “?” suffix would only be used when you want to treat a value as an optional (e.g., when comparing it to nil). For example, for x of type Int?, one could write:

let y = (x? == nil) ? 0 : x

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

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


(Alex Blewitt) #8

Optionality is associated with the type, not the identifier. In addition, how would you deal with type aliases to optional constructs?

typealias MaybeString = String?
var maybe:MaybeString

This doesn’t ‘look’ like an optional value (so would it deserve a ? at the end) but if you have MaybeString? you now have an Optional<Optional<String>>. Should you have ?? there now?

Alex

···

On 4 Dec 2015, at 16:44, Amir Michail <a.michail@me.com> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.


(Amir Michail) #9

You would have:

typealias MaybeString? = String?
var maybe?:MaybeString?

···

On Dec 4, 2015, at 10:57 AM, Alex Blewitt <alex.blewitt@gmail.com> wrote:

On 4 Dec 2015, at 16:44, Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.

Optionality is associated with the type, not the identifier. In addition, how would you deal with type aliases to optional constructs?

typealias MaybeString = String?
var maybe:MaybeString

This doesn’t ‘look’ like an optional value (so would it deserve a ? at the end) but if you have MaybeString? you now have an Optional<Optional<String>>. Should you have ?? there now?

Alex


(Adrian Kashivskyy) #10

I agree with Alex,

Optionality is associated with the type, not the identifier.

Optionals are designed to provide null safety inside a program, not promote using nullables wherever possible. If you use optionals so extensively that you feel the need for special IDE support, maybe you should consider rethinking your API.

By the way,

So for example the following (probable) bug would result in a compile error:
let f = x < 5 // where x is optional and could be nil

I believe nil being less than anything else is an expected behavior which has been introduced by design.

Pozdrawiam – Regards,
Adrian Kashivskyy

···

Wiadomość napisana przez Amir Michail <a.michail@me.com> w dniu 04.12.2015, o godz. 17:17:

On Dec 4, 2015, at 10:57 AM, Alex Blewitt <alex.blewitt@gmail.com <mailto:alex.blewitt@gmail.com>> wrote:

On 4 Dec 2015, at 16:44, Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.

Optionality is associated with the type, not the identifier. In addition, how would you deal with type aliases to optional constructs?

typealias MaybeString = String?
var maybe:MaybeString

This doesn’t ‘look’ like an optional value (so would it deserve a ? at the end) but if you have MaybeString? you now have an Optional<Optional<String>>. Should you have ?? there now?

Alex

You would have:

typealias MaybeString? = String?
var maybe?:MaybeString?

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


(Amir Michail) #11

I agree with Alex,

Optionality is associated with the type, not the identifier.

Optionals are designed to provide null safety inside a program, not promote using nullables wherever possible. If you use optionals so extensively that you feel the need for special IDE support, maybe you should consider rethinking your API.

By the way,

So for example the following (probable) bug would result in a compile error:
let f = x < 5 // where x is optional and could be nil

I believe nil being less than anything else is an expected behavior which has been introduced by design.

It still leads to bugs that are hard to find though.

In any case, I proposed using this code for such a comparison: let f = x? < 5

···

On Dec 4, 2015, at 12:27 PM, Adrian Kashivskyy <adrian.kashivskyy@me.com> wrote:

Pozdrawiam – Regards,
Adrian Kashivskyy

Wiadomość napisana przez Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> w dniu 04.12.2015, o godz. 17:17:

On Dec 4, 2015, at 10:57 AM, Alex Blewitt <alex.blewitt@gmail.com <mailto:alex.blewitt@gmail.com>> wrote:

On 4 Dec 2015, at 16:44, Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.

Optionality is associated with the type, not the identifier. In addition, how would you deal with type aliases to optional constructs?

typealias MaybeString = String?
var maybe:MaybeString

This doesn’t ‘look’ like an optional value (so would it deserve a ? at the end) but if you have MaybeString? you now have an Optional<Optional<String>>. Should you have ?? there now?

Alex

You would have:

typealias MaybeString? = String?
var maybe?:MaybeString?

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


(Adrian Kashivskyy) #12

I agree it may lead to unexpected bugs, but "let f = x? < 5" is not a great alternative, either. We should consider rethinking the behavior of comparison function itself, rather than introduce a new language feature like an operator.

I suggest changing the comparison function's return value to an optional Bool? and consider the following implementation

func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool? {
  if let lhs = lhs, rhs = rhs {
    return lhs < rhs
  } else {
    return nil
  }
}

That way,

// true
Optional(1) < Optional(2)

// nil
Optional(1) < nil

// nil
nil < Optional(2)

Pozdrawiam – Regards,
Adrian Kashivskyy

···

Wiadomość napisana przez Amir Michail <a.michail@me.com> w dniu 04.12.2015, o godz. 18:30:

On Dec 4, 2015, at 12:27 PM, Adrian Kashivskyy <adrian.kashivskyy@me.com <mailto:adrian.kashivskyy@me.com>> wrote:

I agree with Alex,

Optionality is associated with the type, not the identifier.

Optionals are designed to provide null safety inside a program, not promote using nullables wherever possible. If you use optionals so extensively that you feel the need for special IDE support, maybe you should consider rethinking your API.

By the way,

So for example the following (probable) bug would result in a compile error:
let f = x < 5 // where x is optional and could be nil

I believe nil being less than anything else is an expected behavior which has been introduced by design.

It still leads to bugs that are hard to find though.

In any case, I proposed using this code for such a comparison: let f = x? < 5

Pozdrawiam – Regards,
Adrian Kashivskyy

Wiadomość napisana przez Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> w dniu 04.12.2015, o godz. 17:17:

On Dec 4, 2015, at 10:57 AM, Alex Blewitt <alex.blewitt@gmail.com <mailto:alex.blewitt@gmail.com>> wrote:

On 4 Dec 2015, at 16:44, Amir Michail <a.michail@me.com <mailto:a.michail@me.com>> wrote:

I don’t want to remember if a variable is optional. I want to see it in the variable name.

Optionality is associated with the type, not the identifier. In addition, how would you deal with type aliases to optional constructs?

typealias MaybeString = String?
var maybe:MaybeString

This doesn’t ‘look’ like an optional value (so would it deserve a ? at the end) but if you have MaybeString? you now have an Optional<Optional<String>>. Should you have ?? there now?

Alex

You would have:

typealias MaybeString? = String?
var maybe?:MaybeString?

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


(Lily Ballard) #13

There's lots and lots of ways to write bugs in Swift. That's part and
parcel with being a programming language. I disagree that this is a
bug that's hard to find. Do you commonly write code where you don't
understand the types you're working with? If you don't know the types
you're working with, this isn't the only way to accidentally write a
bug that still compiles. Personally, I find the ability to compare
optionals to be very valuable, almost as valuable as the ability to
use == with optionals (which I doubt anyone will argue is a
misfeature). And I don't think I've ever accidentally compared an
optional with < without realizing it. I know, everybody is different,
but deliberate uglification of the language to solve a subjective
issue encountered by some people at the expense of readable code by
everyone else does not seem to me to be a reasonable tradeoff.
Especially since the proposed syntax here is extremely confusing; the
postfix-? already means something else (in fact, it means 3 different
things depending on context).

-Kevin Ballard

···

On Fri, Dec 4, 2015, at 09:30 AM, Amir Michail wrote:

On Dec 4, 2015, at 12:27 PM, Adrian Kashivskyy
<adrian.kashivskyy@me.com> wrote: I believe nil being less than
anything else is an expected behavior which has been introduced by
design.

It still leads to bugs that are hard to find though.

In any case, I proposed using this code for such a comparison: let f
= x? < 5


(Per Melin) #14

Do you commonly write code where you don't understand the types you're
working with?

Here is one type of mistake that I made long after that I should have known
better:

    var x: Int?

    // ...

    switch x {
    case let x where x < 0: // x is still Optional
    default: // ...
    }

Since you write 'if let' so often to unwrap, I kept forgetting that 'case
let' does not, and that there is a special syntax for that: 'case let x?'.

Personally, I find the ability to compare optionals to be very valuable,
almost as valuable as the ability to use == with optionals (which I doubt
anyone will argue is a misfeature).

I have been trying to come up with situations where you would want to
compare two values, knowing that one or both may be nil, with <, <=, > or

=. Other than as for sorting, I can't think of much. I doubt the Swift

team explicitly made this possible without good reason, so I must be
missing something.

Could you please share some examples? It doesn't necessarily have to be
code, just explain the context where this is valuable.

···

On Mon, Dec 7, 2015 at 9:19 AM, Kevin Ballard via swift-evolution < swift-evolution@swift.org> wrote:


(Per Melin) #15

Here is one type of mistake that I made long after that I should have
known better:
[snip]

If you find yourself in danger of forgetting that a value is optional, you
can always adopt a naming convention that makes it apparent. That would
have the same effect as requiring a postfix-? on optional identifiers,
except that it's voluntary.

That would have helped not at all in the example you snipped. But let's not
get hung up on that, I'd rather establish how useful it is to have <, <=, >
and >= cover optional values.

Personally, I find the ability to compare optionals to be very valuable,
almost as valuable as the ability to use == with optionals (which I doubt
anyone will argue is a misfeature).

I have been trying to come up with situations where you would want to
compare two values, knowing that one or both may be nil, with <, <=, > or
>=. Other than as for sorting, I can't think of much. I doubt the Swift
team explicitly made this possible without good reason, so I must be
missing something.

Could you please share some examples? It doesn't necessarily have to be
code, just explain the context where this is valuable.

Sorting is a common one. Another example is just cases where I need to
compare two numbers and at least one number may have been generated by an
optional process. For example:

    if optAry?.count > 3 {

Instead of:

    if let count = optAry?.count where count > 3 {

Which is twice as long, which of course is inconvenient if you do this a
lot, and you don't need the unwrapped value again. A distinct comparison
operator for optional values could solve that.

This can work with non-numeric values too, though usually if I'm
comparing non-numeric values with < then I'm doing some variant on sorting,
which we've already addressed. For example, from my current codebase I find

let sortedJSON = responsesJSON.sort { a, b in

    let a_name = a["name"] as? String

    let b_name = b["name"] as? String

    return a_name?.lowercaseString < b_name?.lowercaseString

}

Instead of:

  let sortedJSON = responsesJSON.sort { a, b in
      let a_name = a["name"] as? String ?? ""
      let b_name = b["name"] as? String ?? ""
      return a_name.lowercaseString < b_name.lowercaseString

  }

Which I think anyone can accept (except that I find ?? to be an eyesore,
but that is a different topic.)

Please note that I'm absolutely not arguing for the suggestion that started
this thread. I just want to understand if it really is necessary to
overload all the comparison operators for (T?, T?) in the first place.

(although were I to rewrite this code I'd switch to using

···

On Mon, Dec 7, 2015 at 8:32 PM, Kevin Ballard <kevin@sb.org> wrote:

On Mon, Dec 7, 2015, at 03:48 AM, Per Melin wrote:
caseInsensitiveCompare() as lowercaseString is needlessly allocating a new
string, but it demonstrates the idea)

I know somewhere in another project I used < with optionals to great
effect for a non-sorting purpose, but I don't remember where to find it
anymore.

In general, my feeling here is that supporting == and < on optionals is
just a specific case of a generally desired property that is Equatable and
Comparable should be supported on all types that are simple wrappers around
existing Equatable/Comparable types. I know this isn't well-defined, but I
mean that since Optional is really just taking the set of values for a type
and adding one additional value, if the type is Comparable/Equatable,
there's an obvious way to define this new inhabiting value as being
Comparable/Equatable with the type, and so it should be done. Similarly, I
think that if I have a tuple (T, U) where both T and U are
Comparable/Equatable, the tuple itself should be (where the Comparable
implementation compares the T value first, and if it's equal then compares
the U value). And any larger tuple where every component element is
Comparable/Equatable should also be Comparable/Equatable. I should also be
able to opt-in to this kind of automatic Comparable/Equatable generation
for structs. I should also be able to get this on other enums where only
one enum variant has associated values, and the associated values are
comparable/equatable (i.e. a generalization of Optional).

-Kevin