Remove nil and NilLiteralConvertible

I don't see a reason to rename or remove the `nil` literal.

But I can come up with a concrete reason to deprecate NilLiteralConvertible: The language has made Optional a very specific thing with `if let` syntax, implicit wrapping, and optional chaining to name a few. But the second most common way (I guess) to create an Optional—by using the `nil` literal—isn't actually guaranteed to create an Optional.

    let condition: Bool
    let x = condition ? 1 : nil
    // error: result values in '? :' expression have mismatching types 'Int' and '_'

An expression like the above doesn't compile because the compiler can't tell what type `nil` should initialise. (Currently, at least Optional<Int> and ImplicitlyUnwrappedOptional<Int> seem possible, but with NilLiteralConvertible, something like a conforming MyJSON could be as well!) This, I think, can be confusing to new users. And life would be simpler if `nil` always stood for `Optional.none`, which would then infer the associated Wrapped type respectfully.

So no, I don't support this idea but I think we should sunset NilLiteralConvertible.

— Pyry

PS. Besides, the above statement will compile with any of the following edits:

    let x = condition ? 1 : Optional.none
    let x = condition ? 1 : nil as Optional
    let x = condition ? 1 : Optional()
    let x = condition ? 1 as Optional : nil
    let x = condition ? 1 as Int? : nil
    let x = condition ? Optional(1) : nil
    let x: Int? = condition ? 1 : nil

···

On 08 Jun 2016, at 23:41, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

(No joking)
Points:

1. When nil was added to the language, we could not infer enumeration type:
if x != Optional.none { ... }

Now it looks like this:
if x != .none { ... }

If at this point we had a proposal to add nil as a replacement for .none, would we accept it?

2. nil is very generic, it only approximately allows to express the intentions.
In case of Optional, .none is clearer. In case of JSON processing, .null is clearer. In case of a semantically nullable struct, NilLiteralConvertible usually goes to default constructor.

3. Too many "empty" things: .none, nil; NSNull, Void, NoReturn types.

4. There should be a single consistent terminology: no value in Swift equals none.

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

My objection to this is that .none is a fairly common member in various enums (besides Optional) and it's a mess already:

enum EventDataRenderType {
  case none
  case tab
  case blockClosed
  case blockOpened
}

let data = self.data
if data.customization?.renderType == .none {
    /// Was it compared to Optional.none, or EventDataRenderType,
    /// since data.customization?.renderType == .tab is completely
    /// valid...
}

If `none` became a keyword as suggested by some, would it be allowed to have .none in other enums?

···

On Jun 8, 2016, at 10:41 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

(No joking)
Points:

1. When nil was added to the language, we could not infer enumeration type:
if x != Optional.none { ... }

Now it looks like this:
if x != .none { ... }

If at this point we had a proposal to add nil as a replacement for .none, would we accept it?

2. nil is very generic, it only approximately allows to express the intentions.
In case of Optional, .none is clearer. In case of JSON processing, .null is clearer. In case of a semantically nullable struct, NilLiteralConvertible usually goes to default constructor.

3. Too many "empty" things: .none, nil; NSNull, Void, NoReturn types.

4. There should be a single consistent terminology: no value in Swift equals none.

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

The same example won’t work in objective-c
number1 and number2 are two different variables that holds different values. When you are assigning number2 = number1 you’re copying the value. And when you are comparing number1 == number2 you are comparing values, that are the same because one is a copy of the another. With objects, it’s the same, as references are values too. Try this:

var number1: AnyObject? = NSObject()
var number2: AnyObject? = number1

number1 === number2 // == does not work here because AnyObject is not Equatable

number1 = NSObject()
number2 === number1 // FALSE.

You can do the same in objective-c with the same result.

···

El 8 jun 2016, a las 19:57, Brandon Knope via swift-evolution <swift-evolution@swift.org> escribió:

Here I have a contrived example (I am bad at trying to explain my point -_-):

When I see nil, I think of reference types. I.e. Objective-C:

NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@"123"];
__weak NSMutableString *reference = mutableString;

reference = mutableString;

[reference appendString:@"456"];
mutableString = nil;

//memory is now deallocated because strong references are eliminated
// BUT reference is now nil! This is expected with reference types

In Objective-C we have to use nil to manage when objects are deallocated. We also have to use __weak to avoid retain cycles etc...

This behavior is consistent with other languages with reference semantics.

However, in Swift, optionals are value types as we all know (though they can wrap reference types):

var number1: Int? = nil
var number2: Int? = number1

number1 == number2

number1 = 3
number2 == number1 // FALSE. This behavior is obviously different from Objective-C and we expect that knowing that it’s a value type

On first look, it looks like reference semantics because you see nil and remember it from other languages. OR you learn this behavior in Swift and expect it to work the same in other languages. Either way the behavior isn’t exactly consistent between all languages. Even nil in Objective-C is different than most languages because you are allowed to send messages to it.

As far as I know, setting:
number1 = nil

does not deallocate number1. It is still an optional with enough space to wrap an Int that happens to just be set to .none currently.

It looks like you are deallocating something if that is the behavior you expect from other languages upon seeing nil.

nil can have similar behaviors in both languages, but they can also have very dissimilar behaviors too.

My main point comes down to: nil makes it look like a pointer and thus makes you see it as a reference type at first glance until you completely retrain yourself. This is not how nil works with values in Swift and I think some might find that surprising down the road when:
A) They learn Swift first and move to another language and see a different behavior than they are use to
B) They come from another language and associate seeing nil with the type being a reference and being surprised

or C…you just have to remember the differences.

I probably made my point even worse but I can only try!
Brandon

On Jun 8, 2016, at 5:37 PM, Sean Heber <sean@fifthace.com <mailto:sean@fifthace.com>> wrote:

When isn’t it?

l8r
Sean

On Jun 8, 2016, at 4:22 PM, Brandon Knope <bknope@me.com <mailto:bknope@me.com>> wrote:

Yes it is the same keyword, but is it the same behavior from other languages?

Brandon

On Jun 8, 2016, at 5:20 PM, Saagar Jha <saagarjha28@gmail.com <mailto:saagarjha28@gmail.com>> wrote:

I think we also need to consider newbies coming from other languages. “nil” being a holdover makes it easier to understand what it means, having a “.none”/“none” duality makes it both seem inconsistent as well as dredge up language implementation details-now you have to explain that Optionals are actually enums internally. Using nil doesn’t lead to this kind of scenario, and they already (mostly) know what it means from other languages.

On Wed, Jun 8, 2016 at 2:13 PM Sean Heber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
If there’s both “.none” and “none”, then I think that’d be more confusing *because of* the naming consistency, IMO. I’d look at that as a newbie and wonder why in the world this word sometimes has a dot and sometimes doesn’t.

If enum cases could be referred to without the leading “.” then perhaps I could get behind this because “none” wouldn’t even need to be a keyword at all in that case, but there are probably difficult ambiguities down that road.

l8r
Sean

On Jun 8, 2016, at 4:04 PM, Brandon Knope <bknope@me.com <mailto:bknope@me.com>> wrote:

1. People will find .none ugly which is why I think it could be replaced by a none keyword. It is awkward
2. none is more descriptive than nil in this case. The case is named none (consistency!) and nil is a holdover from other languages

I understand how nil works in the context of other languages. But looking at Optional:
public enum Optional<Wrapped> : NilLiteralConvertible {

   /// The absence of a value.
   ///
   /// In code, the absence of a value is typically written using the `nil`
   /// literal rather than the explicit `.none` enumeration case.
   case none

   /// The presence of a value, stored as `Wrapped`.
   case some(Wrapped)
}

These are not pointers and they sure look like one when you assign nil to an optional

B

Why would nil be chosen to represent the none case in the absence of other languages?

On Jun 8, 2016, at 4:55 PM, Sean Heber <sean@fifthace.com <mailto:sean@fifthace.com>> wrote:

If you add a new keyword called “none” without the period, but keep allowing “.none” to work because Optional is really an enum… then I don’t really see what has been gained here at all - you’re basically back to nil/.none => 2 ways to say the same thing!

l8r
Sean

On Jun 8, 2016, at 3:52 PM, Brandon Knope via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

.none or a more appropriate keyword like “none” (imo)

Brandon

On Jun 8, 2016, at 4:47 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

It's been pointed out before that Optional being an enum type is treated like an implementation detail. Currently, it is possible to teach the concept of Optional without introducing enum types or generics. How would you do so after elimination of nil?

On Wed, Jun 8, 2016 at 3:41 PM, Антон Жилин <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
(No joking)
Points:

1. When nil was added to the language, we could not infer enumeration type:
if x != Optional.none { ... }

Now it looks like this:
if x != .none { ... }

If at this point we had a proposal to add nil as a replacement for .none, would we accept it?

2. nil is very generic, it only approximately allows to express the intentions.
In case of Optional, .none is clearer. In case of JSON processing, .null is clearer. In case of a semantically nullable struct, NilLiteralConvertible usually goes to default constructor.

3. Too many "empty" things: .none, nil; NSNull, Void, NoReturn types.

4. There should be a single consistent terminology: no value in Swift equals none.

- Anton

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

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

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

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

Would you allow this?

let myStrings = ["s1": "hello, world", "s2": "something else"]
myStrings["s2"] = .none

If so, that would make this example strange:

enum Stuff {
case Bone, Dome, Chrome
}

let myStuff: [String:Stuff] = ["s1": .Bone, "s2": .Dome]
myStuff["s2"] = .none
myStuff["s1"] = .Chrome

In this last example, to me it seems less clear that a dictionary index is
dropped than if nil was used.

Why do you think that is? Why does nil express something different to you than Optional.none?

While I do think `nil` expresses something slightly different than
`Optional.none`, that is not why I think this example is unclear. When
assigning and clearing multilpe enum values in a dictionary on consecutive lines
`.none` is less visually distinct from `nil`[1] and takes a little more
care to recognize that `.none` is `Optional.none` and not `Stuff.none`.

My guess is that you are thinking about it as an object being set to
nil and thus being deleted when there is no strong reference to it.

Nope, I'm not thinking about references. I do think there is a slight
conceptual difference between literal `nil` and `Optional.none`: the
former is a literal representation of nothing, and the later a value
that acts as a placeholder for nothing.

Disallowing `nil` in favor of `.none` would only make sense to me if you
also removed the ability to assign other literals or other values
without wrapping the value with .some(_) (I'm not sure if you'd have to
write Optional<T>.some(_) to get type inference working correctly.
Removing `nil` would only make sense to me if things in Swift were more
like Scala regarding Option type assignment;

this:

var myInt: Int?
myInt = 3
myInt = nil

becomes this:

var myInt: Int?
myInt = .some(3)
myInt = .none

Personally, not needing to perform this sort of wrapping is something I
prefer about writing Swift vs Scala.

It has been discussed that `nil` might confuse users to thinking it was
the same `nil` as in other languages (e.g. 0 in Objective-C). While
maybe a less common form of confusion, the same could be said for `.none`
where in Swift `.none` can't be stored in a Dictionary but it can be in
Scala.

Also, the fact that nil is used for any kind of nothingness not just
Optional.none (nil unsafe pointers, etc.) it makes sense to me that
nil is used for all assignments to types that can be nothing (just
because it is implemented with an enum, I don't see why that makes
Optional.none special vs other things that are currently nil convertible).

···

On Wed, Jun 08 2016 at 05:16:26 PM, Brandon Knope <bknope@me.com> wrote:

On Jun 8, 2016, at 5:03 PM, Roth Michaels via swift-evolution <swift-evolution@swift.org> wrote:

--
Roth

[1]: I don't think syntax highlighting alone should be a solution.

It’s only as leaky as you want it to be. We have two shipping apps with large codebases using Swift, and we *never* refer to Optional enum directly or to its enum .some or .none cases anywhere in our code.

Personally, I’d much prefer to keep nil.

···

On Jun 8, 2016, at 4:59 PM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

Is it really an implementation detail? It is very leaky if it is one because it is highly exposed to everyone.