Implicit Optionals for Tuples & Tuples as Function Parameter


(Muhammad Tahir Vali) #1

Im curious to know the reasoning behind why implicit-wrapped optionals
aren't allowed when creating tuples. Below is an example with type aliases
and anonymous tuples.

ex.

typealias Name = (first: String!, middle: String?, last: String!)

typealias Name = (first: String!, middle: String?, last: String!)!

var name : (first: String!, middle: String?, last: String!)
var name : (first: String!, middle: String?, last: String!)!

error from all 4 examples above:
Implicitly unwrapped optionals are only allowed at top level and as
function results

I also noticed that I can modify tuples using functions ONLY if I use
*inout*.

func name(Person : inout (first: String?, middle: String?, last: String?)) {

    Person.first = "John"

    Person.last = "Doe"

}

OR

func name(Person : inout Name) {

    Person.first = "John"

    Person.last = "Doe"

}

This is because tuples are passed into functions as 'let' constants. Why
not add the ability to modify a copy of the tuple inside the function ?

···

--
Best Regards,

Muhammad T. Vali


(Hooman Mehr) #2

Since Swift 3.0, they are no longer a normal type like Optional<T>. See SR-0054 <https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md>

···

On Nov 11, 2016, at 11:54 AM, Muhammad Tahir Vali via swift-evolution <swift-evolution@swift.org> wrote:

Im curious to know the reasoning behind why implicit-wrapped optionals aren't allowed when creating tuples. Below is an example with type aliases and anonymous tuples.

ex.
typealias Name = (first: String!, middle: String?, last: String!)
typealias Name = (first: String!, middle: String?, last: String!)!
var name : (first: String!, middle: String?, last: String!)
var name : (first: String!, middle: String?, last: String!)!

error from all 4 examples above:
Implicitly unwrapped optionals are only allowed at top level and as function results

I also noticed that I can modify tuples using functions ONLY if I use inout.

func name(Person : inout (first: String?, middle: String?, last: String?)) {
    Person.first = "John"
    Person.last = "Doe"
}

OR

func name(Person : inout Name) {
    Person.first = "John"
    Person.last = "Doe"
}

This is because tuples are passed into functions as 'let' constants. Why not add the ability to modify a copy of the tuple inside the function ?

--
Best Regards,

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


(John McCall) #3

Im curious to know the reasoning behind why implicit-wrapped optionals aren't allowed when creating tuples. Below is an example with type aliases and anonymous tuples.

ex.
typealias Name = (first: String!, middle: String?, last: String!)
typealias Name = (first: String!, middle: String?, last: String!)!
var name : (first: String!, middle: String?, last: String!)
var name : (first: String!, middle: String?, last: String!)!

error from all 4 examples above:
Implicitly unwrapped optionals are only allowed at top level and as function results

This is intentionally-designed behavior. Preventing IUO at arbitrary locations was SE-0054:
  https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md

I also noticed that I can modify tuples using functions ONLY if I use inout.

func name(Person : inout (first: String?, middle: String?, last: String?)) {
    Person.first = "John"
    Person.last = "Doe"
}

OR

func name(Person : inout Name) {
    Person.first = "John"
    Person.last = "Doe"
}

This is because tuples are passed into functions as 'let' constants. Why not add the ability to modify a copy of the tuple inside the function ?

We used to allow "var" parameters, but they were removed in SE-0003:
  https://github.com/apple/swift-evolution/blob/master/proposals/0003-remove-var-parameters.md

Tuples are values like any other; I don't know why they would warrant a special exception to that rule.

John.

···

On Nov 11, 2016, at 11:54 AM, Muhammad Tahir Vali via swift-evolution <swift-evolution@swift.org> wrote:


(Muhammad Tahir Vali) #4

Thank you. Overlooked that in the Swift 3 release notes.

···

On Fri, Nov 11, 2016 at 3:43 PM, John McCall <rjmccall@apple.com> wrote:

On Nov 11, 2016, at 11:54 AM, Muhammad Tahir Vali via swift-evolution < > swift-evolution@swift.org> wrote:

Im curious to know the reasoning behind why implicit-wrapped optionals
aren't allowed when creating tuples. Below is an example with type aliases
and anonymous tuples.

ex.
typealias Name = (first: String!, middle: String?, last: String!)
typealias Name = (first: String!, middle: String?, last: String!)!
var name : (first: String!, middle: String?, last: String!)
var name : (first: String!, middle: String?, last: String!)!

error from all 4 examples above:
Implicitly unwrapped optionals are only allowed at top level and as
function results

This is intentionally-designed behavior. Preventing IUO at arbitrary
locations was SE-0054:
  https://github.com/apple/swift-evolution/blob/master/
proposals/0054-abolish-iuo.md

I also noticed that I can modify tuples using functions ONLY if I use
*inout*.

func name(Person : inout (first: String?, middle: String?, last: String?))
{
    Person.first = "John"
    Person.last = "Doe"
}

OR

func name(Person : inout Name) {
    Person.first = "John"
    Person.last = "Doe"

}

This is because tuples are passed into functions as 'let' constants. Why
not add the ability to modify a copy of the tuple inside the function ?

We used to allow "var" parameters, but they were removed in SE-0003:
  https://github.com/apple/swift-evolution/blob/master/
proposals/0003-remove-var-parameters.md

Tuples are values like any other; I don't know why they would warrant a
special exception to that rule.

John.

--
Best Regards,

Muhammad T. Vali


(Haravikk) #5

Im curious to know the reasoning behind why implicit-wrapped optionals aren't allowed when creating tuples. Below is an example with type aliases and anonymous tuples.

ex.
typealias Name = (first: String!, middle: String?, last: String!)
typealias Name = (first: String!, middle: String?, last: String!)!
var name : (first: String!, middle: String?, last: String!)
var name : (first: String!, middle: String?, last: String!)!

error from all 4 examples above:
Implicitly unwrapped optionals are only allowed at top level and as function results

I think in general the direction is leaning towards getting rid of IUO's entirely if possible, as a lot of things that people use them for could be handled better in other ways; the only times I've ever used them is to get around issues with constructors (namely the requirement to initialise everything before other methods can be called), but that could be solved by detecting or marking methods that would be safe for that.

I also noticed that I can modify tuples using functions ONLY if I use inout.

func name(Person : inout (first: String?, middle: String?, last: String?)) {
    Person.first = "John"
    Person.last = "Doe"
}

OR

func name(Person : inout Name) {
    Person.first = "John"
    Person.last = "Doe"
}

This is because tuples are passed into functions as 'let' constants. Why not add the ability to modify a copy of the tuple inside the function ?

The ability to specify function arguments as mutable was removed to avoid confusion with inout as it wasn't completely obvious that with a var what you're modifying is a copy. However you can make a mutable copy with shadowing, like-so:

  func name(Person:(first:String?, middle:String?, last:String?) { var Person = Person // Person is now a mutable copy
    Person.first = "John"
    Person.last = "Doe"
  }

Obviously with the caveat that these changes don't exist outside of that scope, so unless you make use of them there that code will likely just get optimised away.

···

On 11 Nov 2016, at 19:54, Muhammad Tahir Vali via swift-evolution <swift-evolution@swift.org> wrote:


#6

I’ll mention this here since it’s related to tuples and optionals. Starting
with this setup:

var x, y: Int?
func f() -> (Int, Int) { return (0, 1) }

This fails to compile:

(x, y) = f() // Error: Cannot express tuple conversion '(Int, Int)' to
'(Int?, Int?)'

But this works fine:

func g() -> Int { return 2 }
(x, y) = (g(), g())

What is going on, why does the first one fail, and is this a bug or does it
need a proposal to fix?

Nevin


(John McCall) #7

It's a bug. The error message is actually subtly telling you the problem: the type-checker literally can't express the opaque tuple conversion in the AST; when it's a raw tuple expression, it can push the element conversions into the element expressions, but it can't do that with an opaque tuple. It's a silly restriction because of an unfortunate representational decision.

John.

···

On Nov 11, 2016, at 1:37 PM, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:
I’ll mention this here since it’s related to tuples and optionals. Starting with this setup:

var x, y: Int?
func f() -> (Int, Int) { return (0, 1) }

This fails to compile:

(x, y) = f() // Error: Cannot express tuple conversion '(Int, Int)' to '(Int?, Int?)'

But this works fine:

func g() -> Int { return 2 }
(x, y) = (g(), g())

What is going on, why does the first one fail, and is this a bug or does it need a proposal to fix?