Immutable Structures


(Lino Rosa) #1

I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If
structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed
around multiple threads removes the by-value semantics seamlessly. The
resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be
passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable
parameters. Also the `var` keyword before a structure could be used to
denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.


(Félix Cloutier) #2

The current choice is that if you need pass-by-value semantics, you use a struct; if you need pass-by-reference semantics, you use a class. This is almost only relevant when structs are mutable: the only semantic difference between a struct and a class is that mutating a struct won't have an impact on the original. If structs were immutable, there would be absolutely no distinction between a struct and a read-only class. In my opinion, immutable structs would make the choice much more ambiguous than it is right now.

Changing this would have a major impact. Arrays, dictionaries, sets and strings are all pass-by-value right now. It would be a massively breaking change to make them plainly immutable or to make them reference types. It would also throw a wrench into C interop, which is critical for Swift to succeed in a non-ObjC environment (like Linux).

I personally don't see a problem with the current semantics and I don't like the impact, so I'm not in favor of it.

Félix

···

Le 23 déc. 2015 à 10:44:49, Lino Rosa via swift-evolution <swift-evolution@swift.org> a écrit :

I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable parameters. Also the `var` keyword before a structure could be used to denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Douglas Gregor) #3

Swift’s structures, enums, and standard library collections provide value semantics, which is far more useful than true immutability because it gives you immutability guaranteed when you want them (“let”) and efficient local mutation when you need it (“var”) . If you haven’t seen the “Building Better Apps with Value Types in Swift” talk from WWDC 2015, I suggest you check it out to get a sense of how value types work in Swift:

  https://developer.apple.com/videos/play/wwdc2015-414/

We’re very happy with value semantics as a programming model, so the likelihood of moving to a model where a value of struct type is always immutable is effectively zero. My hope is that the talk above—or other resources about value semantics in Swift—will convince you as thoroughly as it convinced us :wink:

  - Doug

···

On Dec 23, 2015, at 7:44 AM, Lino Rosa via swift-evolution <swift-evolution@swift.org> wrote:

I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable parameters. Also the `var` keyword before a structure could be used to denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.


(Ian Ynda-Hummel) #4

I thought structures were immutable and mutating functions actually just
created new structures, thus maintaining the by value semantics.

···

On Wed, Dec 23, 2015 at 10:45 AM Lino Rosa via swift-evolution < swift-evolution@swift.org> wrote:

I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If
structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed
around multiple threads removes the by-value semantics seamlessly. The
resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be
passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable
parameters. Also the `var` keyword before a structure could be used to
denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #5

I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable parameters. Also the `var` keyword before a structure could be used to denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.

Swift’s structures, enums, and standard library collections provide value semantics, which is far more useful than true immutability because it gives you immutability guaranteed when you want them (“let”) and efficient local mutation when you need it (“var”) . If you haven’t seen the “Building Better Apps with Value Types in Swift” talk from WWDC 2015, I suggest you check it out to get a sense of how value types work in Swift:

   https://developer.apple.com/videos/play/wwdc2015-414/

We’re very happy with value semantics as a programming model, so the likelihood of moving to a model where a value of struct type is always immutable is effectively zero. My hope is that the talk above—or other resources about value semantics in Swift—will convince you as thoroughly as it convinced us :wink:

+1,000,000. This is one of the best aspects of Swift IMO.

···

Sent from my iPad

On Dec 23, 2015, at 3:57 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 23, 2015, at 7:44 AM, Lino Rosa via swift-evolution <swift-evolution@swift.org> wrote:

   - Doug

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


(Lino Rosa) #6

Reassigning structures will create new ones. Mutating functions and
reassigning its properties won't: they mutate it.

···

On Wed, Dec 23, 2015 at 10:51 AM Ian Ynda-Hummel <ianynda@gmail.com> wrote:

I thought structures were immutable and mutating functions actually just
created new structures, thus maintaining the by value semantics.
On Wed, Dec 23, 2015 at 10:45 AM Lino Rosa via swift-evolution < > swift-evolution@swift.org> wrote:

I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If
structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed
around multiple threads removes the by-value semantics seamlessly. The
resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would
be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable
parameters. Also the `var` keyword before a structure could be used to
denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.

_______________________________________________

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


(Rudolf Adamkovič) #7

BTW, structures are immutable yet they can have mutating functions.

I fully understand how this works as a language user but I wonder...

Isn’t there a better keyword (than “mutating”) that we could use here?

R+

···

On 23 Dec 2015, at 16:51, Ian Ynda-Hummel via swift-evolution <swift-evolution@swift.org> wrote:

I thought structures were immutable and mutating functions actually just created new structures, thus maintaining the by value semantics.
On Wed, Dec 23, 2015 at 10:45 AM Lino Rosa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable parameters. Also the `var` keyword before a structure could be used to denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.
_______________________________________________
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


(Lino Rosa) #8

*Paul Cantrell:*

*> “Ah, OK, sure … but why is this a problem? You changed the declaration!
Of course it behaves differently. Changing a declaration can transparently
change behavior in any number of circumstances. The following code still
compiles if you change “Int” to “UInt8,” but it crashes:”*

Good point, but I still think this is on a different class of problem
because 1) it’s really hard to track where we were relying on value
semantics before and adapt it to using classes and 2) the sort of bugs that
would creep out wouldn’t probably be crashes but weird side-effects
incredibly hard to track.

*David Owens II:*

*"Did you mean “var” there? (sidenote: var is being removed from the

function call site)"*

Yes I meant it, or it won’t compile. You’re right, they’re equivalent. Oh
the `var` is being deprecated there? Nice to know :slight_smile:

*"I agree that this type of refactoring is inherently fragile, but I

don’t see how having “immutable” structs changes this."*

It would solve it (although quite indirectly) because we couldn’t have had
code that mutated the structure before the said refactoring. In other
words, since we weren’t relying on the value semantics before (because of
immutability) then refactoring to classes wouldn’t be fragile.

*Rudolf Adamkovič:*

*"Isn’t there a better keyword (than “mutating”) that we could use here?"*

I don’t understand why we need the `mutating` keyword in the first place.
Is it for readability? Right now the compiler knows when a function mutates
a property and forces us to write `mutating`. Couldn’t it just fail
compiling when try to call a mutation function but we’re not allowed?

Douglas Gregor:

I realize there’s substantial personal opinion involved in this - and I’m
vastly outnumbered here :slight_smile: Still, I’m replying with my thoughts after
watching your presentation. Maybe that clarifies some of my points and, who
knows, even increases my odds to 1%?

-- The temperature class example --
You make a point of how shared references sometimes result unintended
consequences. However, they’re only unintended because the fictional
developer in the example is using classes and expects value semantics.
Couldn’t one make the opposite argument, where the developer expected
reference semantics while using structures?

-- Immutability sometimes leads to awkward interfaces
This is the "awkward" version from the video:
`home.oven.temperature = Temperature(fahrenheit: temp.fahrenheit + 10.0)`

You could make it not awkward by implementing `+` and `-` in the global
scope so it adds numbers and `Temperature` together. This would bring it
back to:
`home.oven.temperature = temp + 10.0`. You already do it with strings: `let
foobar = "Foo" + "Bar"`.

By the way, structures as value types (arguably) create some awkwardness
and certainly add special cases to the language
1) `let` and `var` aren’t just about reassignment anymore. It depends on
the context: for classes it’s still about reassignment; for structures it’s
about reassignment and mutability (well, also depending on whether the
properties of the structure are `let` or `var` themselves).
2) the `mutating` keyword on protocol extensions is only there for
structures and enums - and doesn’t even enforce them to actually mutate
anything.
3) the class specific protocol extensions.

-- Immutability does not map efficiently to the machine model --
Yes, but that’s only an issue if the language is 100% immutable.

-- Integers are value types --
Aren’t they also immutable?

-- Arrays are value types --
Why? I would honestly like to know. I think all languages I’ve used in the
past had arrays as reference types. Is it just because of equality?

-- CGPoints are value types --
Other than digging into the documentation, how can we tell it has value
semantics? We can’t just skim the code and understand it anymore - we have
to dig into class/structure definitions to figure out whether each thing is
a value or reference. And we’ll have to do it constantly because things
that work with structures would be disastrous for classes.

-- Freedom from race conditions --
Only accidental race conditions. Often memory is shared because it must be.
Those are the tricky ones to solve.

-- Reference types as properties of structures --
Why even allow it? Isn’t the whole point of structures to be used in small,
simple cases? Allowing reference types inside opens up a can of worms with
these “forReading/forWriting” methods…

Finally, thanks for the link to the video Douglas. I hope I didn’t sound
combative. It wasn’t my intention. Sadly I wasn't converted. Perhaps next
year? :slight_smile:

···

On Wed, Dec 23, 2015 at 6:13 PM Matthew Johnson <matthew@anandabits.com> wrote:

Sent from my iPad

> On Dec 23, 2015, at 3:57 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
>> On Dec 23, 2015, at 7:44 AM, Lino Rosa via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> I believe the language would be improved by making structures immutable.
>>
>> 1) The choice between classes and structures isn’t clear right now. If
structures were immutable it would be natural to use them as value objects.
>>
>> 2) Refactoring a mutable structure into a class when it’s being passed
around multiple threads removes the by-value semantics seamlessly. The
resulting mutable class isn’t thread-safe.
>>
>> 2.1) Even when passed around a single thread, the resulting class would
be passed by reference, so any mutations would have unintended consequences.
>>
>> 3) We could probably remove some syntax: `mutating` keyword and
variable parameters. Also the `var` keyword before a structure could be
used to denote reassignment (not mutability), just as it does with classes.
>>
>> Of corse I might not be seeing the whole picture, so please weigh in.
>
> Swift’s structures, enums, and standard library collections provide
value semantics, which is far more useful than true immutability because it
gives you immutability guaranteed when you want them (“let”) and efficient
local mutation when you need it (“var”) . If you haven’t seen the “Building
Better Apps with Value Types in Swift” talk from WWDC 2015, I suggest you
check it out to get a sense of how value types work in Swift:
>
> https://developer.apple.com/videos/play/wwdc2015-414/
>
> We’re very happy with value semantics as a programming model, so the
likelihood of moving to a model where a value of struct type is always
immutable is effectively zero. My hope is that the talk above—or other
resources about value semantics in Swift—will convince you as thoroughly as
it convinced us :wink:

+1,000,000. This is one of the best aspects of Swift IMO.

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


(Paul Cantrell) #9

Structs behave _as if_ they are immutable and every mutation creates a copy.

The compiler may — and usually does — optimize this away as a direct mutation. (And then there’s inout, which is tricky.)

It’s a brilliant model, and I believe a strong one as it stands. Lino, I believe this addresses your #1 and #3. I’m afraid I don’t follow your #2. Can you elaborate?

Cheers, P

···

On Dec 23, 2015, at 10:15 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

No, this is a consequence of structures being passed by value to property accessors. The getter doesn't return a reference to the frame, it returns a copy of it, so it is accompanied by a hidden set operation where it replaces the whole thing.

Félix

Le 23 déc. 2015 à 11:09:43, Kevin Lundberg via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

I believe Ian is correct in that changing any struct's value in any way creates a whole new struct.
See http://swiftstub.com/635749345 for proof (the didSet property observer fires every time a change happens to the struct).

On Dec 23, 2015, at 11:00 AM, Lino Rosa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Reassigning structures will create new ones. Mutating functions and reassigning its properties won't: they mutate it.
On Wed, Dec 23, 2015 at 10:51 AM Ian Ynda-Hummel <ianynda@gmail.com <mailto:ianynda@gmail.com>> wrote:
I thought structures were immutable and mutating functions actually just created new structures, thus maintaining the by value semantics.
On Wed, Dec 23, 2015 at 10:45 AM Lino Rosa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable parameters. Also the `var` keyword before a structure could be used to denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.
_______________________________________________
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

_______________________________________________
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


(Kevin Lundberg) #10

I believe Ian is correct in that changing any struct's value in any way creates a whole new struct.
See http://swiftstub.com/635749345 for proof (the didSet property observer fires every time a change happens to the struct).

···

On Dec 23, 2015, at 11:00 AM, Lino Rosa via swift-evolution <swift-evolution@swift.org> wrote:

Reassigning structures will create new ones. Mutating functions and reassigning its properties won't: they mutate it.
On Wed, Dec 23, 2015 at 10:51 AM Ian Ynda-Hummel <ianynda@gmail.com <mailto:ianynda@gmail.com>> wrote:
I thought structures were immutable and mutating functions actually just created new structures, thus maintaining the by value semantics.
On Wed, Dec 23, 2015 at 10:45 AM Lino Rosa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable parameters. Also the `var` keyword before a structure could be used to denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.
_______________________________________________
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


(Félix Cloutier) #11

No, this is a consequence of structures being passed by value to property accessors. The getter doesn't return a reference to the frame, it returns a copy of it, so it is accompanied by a hidden set operation where it replaces the whole thing.

Félix

···

Le 23 déc. 2015 à 11:09:43, Kevin Lundberg via swift-evolution <swift-evolution@swift.org> a écrit :

I believe Ian is correct in that changing any struct's value in any way creates a whole new struct.
See http://swiftstub.com/635749345 for proof (the didSet property observer fires every time a change happens to the struct).

On Dec 23, 2015, at 11:00 AM, Lino Rosa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Reassigning structures will create new ones. Mutating functions and reassigning its properties won't: they mutate it.
On Wed, Dec 23, 2015 at 10:51 AM Ian Ynda-Hummel <ianynda@gmail.com <mailto:ianynda@gmail.com>> wrote:
I thought structures were immutable and mutating functions actually just created new structures, thus maintaining the by value semantics.
On Wed, Dec 23, 2015 at 10:45 AM Lino Rosa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable parameters. Also the `var` keyword before a structure could be used to denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.
_______________________________________________
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

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


(Lino Rosa) #12

Félix Cloutier*: *Yes immutable structures would look just like read-only
classes, but I don't think this makes the choice more ambiguous. The use of
structures could be encouraged whenever possible with a clear message: "Is
it all immutable? Use structures then". Perhaps even be explicit on the
performance implications of stack storage. I believe the real problem is C
interop, and for that I have no arguments.

Paul Cantrell: Sure, example below. Changing `struct Position` into `class
Position` would still compile and print 30 instead.

···

==============================
struct Position {
  var x: Int
  var y: Int

  init(x: Int, y: Int) {
    self.x = x
    self.y = y
  }
}

func move(var position: Position) {
  position.x += 20
}

var p1 = Position(x: 10, y: 10)
move(p1)

print(p1.x) // prints 10

On Wed, Dec 23, 2015 at 11:24 AM Paul Cantrell <cantrell@pobox.com> wrote:

Structs behave _as if_ they are immutable and every mutation creates a
copy.

The compiler may — and usually does — optimize this away as a direct
mutation. (And then there’s inout, which is tricky.)

It’s a brilliant model, and I believe a strong one as it stands. Lino, I
believe this addresses your #1 and #3. I’m afraid I don’t follow your #2.
Can you elaborate?

Cheers, P

On Dec 23, 2015, at 10:15 AM, Félix Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

No, this is a consequence of structures being passed by value to property
accessors. The getter doesn't return a reference to the frame, it returns a
copy of it, so it is accompanied by a hidden set operation where it
replaces the whole thing.

Félix

Le 23 déc. 2015 à 11:09:43, Kevin Lundberg via swift-evolution < > swift-evolution@swift.org> a écrit :

I believe Ian is correct in that changing any struct's value in any way
creates a whole new struct.
See http://swiftstub.com/635749345 for proof (the didSet property
observer fires every time a change happens to the struct).

On Dec 23, 2015, at 11:00 AM, Lino Rosa via swift-evolution < > swift-evolution@swift.org> wrote:

Reassigning structures will create new ones. Mutating functions and
reassigning its properties won't: they mutate it.
On Wed, Dec 23, 2015 at 10:51 AM Ian Ynda-Hummel <ianynda@gmail.com> > wrote:

I thought structures were immutable and mutating functions actually just
created new structures, thus maintaining the by value semantics.
On Wed, Dec 23, 2015 at 10:45 AM Lino Rosa via swift-evolution < >> swift-evolution@swift.org> wrote:

I believe the language would be improved by making structures immutable.

1) The choice between classes and structures isn’t clear right now. If
structures were immutable it would be natural to use them as value objects.

2) Refactoring a mutable structure into a class when it’s being passed
around multiple threads removes the by-value semantics seamlessly. The
resulting mutable class isn’t thread-safe.

2.1) Even when passed around a single thread, the resulting class would
be passed by reference, so any mutations would have unintended consequences.

3) We could probably remove some syntax: `mutating` keyword and variable
parameters. Also the `var` keyword before a structure could be used to
denote reassignment (not mutability), just as it does with classes.

Of corse I might not be seeing the whole picture, so please weigh in.

_______________________________________________

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

_______________________________________________
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


(TJ Usiyan) #13

I don’t understand why we need the `mutating` keyword in the first place.
Is it for readability? Right now the compiler knows when a function mutates
a property and forces us to write `mutating`. Couldn’t it just fail
compiling when try to call a mutation function but we’re not allowed?

I strongly disagree with this sentiment. I agree that the compiler can
figure it out without us in many cases but I appreciate knowing
*explicitly* which parts of an API will mutate a value. It is helpful for
both the vendor and consumer of the API to require that keyword.


(Lino Rosa) #14

To me documentation plus the type signatures are generally enough. However
I could probably still agree with you if mutating was also used in classes.
What's the point of having it only on structures?

···

On Fri, Dec 25, 2015 at 12:32 T.J. Usiyan <griotspeak@gmail.com> wrote:

I don’t understand why we need the `mutating` keyword in the first place.
Is it for readability? Right now the compiler knows when a function mutates
a property and forces us to write `mutating`. Couldn’t it just fail
compiling when try to call a mutation function but we’re not allowed?

I strongly disagree with this sentiment. I agree that the compiler can
figure it out without us in many cases but I appreciate knowing
*explicitly* which parts of an API will mutate a value. It is helpful for
both the vendor and consumer of the API to require that keyword.


(David Owens II) #15

I’m confused by your example below. Your move() function is equivalent to this:

func move(position: Position) {
    var copy = position
    copy.x += 20
}

Did you mean “var” there? (sidenote: var is being removed from the function call site)

Structs are immutable. It’s only with a var-declaration and a mutating function or it’s exposed properties, or the passing via inout, that structs appear to become immutable, but even that is a copy-on-write behavior. Like others have mentioned, the optimizer can remove this copy in many places for efficiency gains.

For instance, this is how you would change the incoming struct:

func move(inout position: Position) {
    position.x += 20
}

var p1 = Position(x: 10, y: 10)
move(&p1)

This will print 30 both with struct or class.

1) The choice between classes and structures isn’t clear right now. If structures were immutable it would be natural to use them as value objects.

If you have a value-type type and it supports equality, then a struct is the “right” choice. That’s the basic guideline. So anything you wish to treat as a value and have value-semantics (which is basically copy-on-write), use a struct. That seems like what you are saying, and that’s already the case.

2) Refactoring a mutable structure into a class when it’s being passed around multiple threads removes the by-value semantics seamlessly. The resulting mutable class isn’t thread-safe.

Classes, by definition, remove value-semantics. I agree that this type of refactoring is inherently fragile, but I don’t see how having “immutable” structs changes this.

-David


(Paul Cantrell) #16

Ah, OK, sure … but why is this a problem? You changed the declaration! Of course it behaves differently. Changing a declaration can transparently change behavior in any number of circumstances. The following code still compiles if you change “Int” to “UInt8,” but it crashes:

    struct Position {
      var x: Int
      var y: Int
      
      init(x: Int, y: Int) {
        self.x = x
        self.y = y
      }
    }

    func move(var position: Position) {
      position.x += 200
    }

    var p1 = Position(x: 100, y: 100)
    move(p1)

    print(p1.x)

I could see this argument having some traction for protocol extensions, which can be attached to structs or classes with wildly different results. Protocols can limit themselves to classes only; can they limit themselves to structs as well? I don’t think so…. That could be a useful language change.

Cheers, P

···

On Dec 23, 2015, at 10:37 AM, Lino Rosa <lino.aguiar.rosa@gmail.com> wrote:

Paul Cantrell: Sure, example below. Changing `struct Position` into `class Position` would still compile and print 30 instead.

==============================
struct Position {
  var x: Int
  var y: Int
  
  init(x: Int, y: Int) {
    self.x = x
    self.y = y
  }
}

func move(var position: Position) {
  position.x += 20
}

var p1 = Position(x: 10, y: 10)
move(p1)

print(p1.x) // prints 10


(Brent Royal-Gordon) #17

However I could probably still agree with you if mutating was also used in classes. What's the point of having it only on structures?

In a regular method, `self` is a regular (constant) parameter, but in a `mutating` method, `self` is `inout` so that it can be mutated and those mutations will reach the caller's copy of the instance. There's no need for an `inout` `self` on reference types, because the mutations are performed on the shared instance which both the caller and callee have a reference to, so `mutating` only really makes sense for value types.

···

--
Brent Royal-Gordon
Architechies


(Wallacy) #18

*"To me documentation plus the type signatures are generally enough.
However I could probably still agree with you if mutating was also used in
classes. What's the point of having it only on structures?"*

Because, structs ARE immutable by default. The mutating keyword says to
holding variable to copy-change and re-assign the value type. You never
notice the didSet called after mutation?

*"By the way, structures as value types (arguably) create some awkwardness
and certainly add special cases to the language*
*1) `let` and `var` aren’t just about reassignment anymore. It depends on
the context: for classes it’s still about reassignment; for structures it’s
about reassignment and mutability (well, also depending on whether the
properties of the structure are `let` or `var` themselves).*
*2) the `mutating` keyword on protocol extensions is only there for
structures and enums - and doesn’t even enforce them to actually mutate
anything.*
*3) the class specific protocol extensions."*

1) Its not true. Its just about the reassignment. But for value-types in
automatic the process of copy-change and assign.
2) because only value types need this keyword. And the problem of do not
enforce the mutation maybe can be a future improvement, it's not a big
deal, you can propose this adjustment.
3) what's the problem here?

*"Good point, but I still think this is on a different class of problem
because 1) it’s really hard to track where we were relying on value
semantics before and adapt it to using classes and 2) the sort of bugs that
would creep out wouldn’t probably be crashes but weird side-effects
incredibly hard to track."*

Can you elaborate this? Does not appear a real world problem.
Change struct for class will always be a "break change". Its not free of
bugs in any language.

*"-- Integers are value types --*
*Aren’t they also immutable?"*

yes....

*"-- Arrays are value types --*
*Why? I would honestly like to know. I think all languages I’ve used in the
past had arrays as reference types. Is it just because of equality? *
*"*

This ship sailed a long time ago.... This is a big feature in swift, on the
old swift forum may you can see the role discussion about that.

Value type arrays are something with I miss in other languages.

*"-- CGPoints are value types --*
*Other than digging into the documentation, how can we tell it has value
semantics? We can’t just skim the code and understand it anymore - we have
to dig into class/structure definitions to figure out whether each thing is
a value or reference. And we’ll have to do it constantly because things
that work with structures would be disastrous for classes."*

hu? Just check if the type is a struct or a enum! So will be a value type.
Whats the problem here?

*"-- Freedom from race conditions --*
*Only accidental race conditions. Often memory is shared because it must
be. Those are the tricky ones to solve.*
*"*

So, "accidental" are the name of most common bugs right? All bugs are
"accidental".... The same argument you can use for avoid Optionals.

*"-- Reference types as properties of structures --*
*Why even allow it? Isn’t the whole point of structures to be used in
small, simple cases? Allowing reference types inside opens up a can of
worms with these “forReading/forWriting” methods…*
*"*

No, the whole point of structs are not to be used in small and simple
cases, not on Swift, in swift um Swift are first class citizen and can be
use for complex data structure, like Array and Strings. You can make a
private shared buffer behind the scenes.

"Finally, thanks for the link to the video Douglas. I hope I didn’t sound
combative. It wasn’t my intention. Sadly I wasn't converted. Perhaps next
year? :slight_smile:
"

FWIW:
Try this one: https://developer.apple.com/videos/play/wwdc2015-408/ (
Protocol-Oriented
Programming in Swift )

It explains (too) why structs are so important in Swift. Spoiler: Because
its not a OO primary language.

···

Em sex, 25 de dez de 2015 às 15:47, Lino Rosa via swift-evolution < swift-evolution@swift.org> escreveu:

On Fri, Dec 25, 2015 at 12:32 T.J. Usiyan <griotspeak@gmail.com> wrote:

I don’t understand why we need the `mutating` keyword in the first
place. Is it for readability? Right now the compiler knows when a function
mutates a property and forces us to write `mutating`. Couldn’t it just fail
compiling when try to call a mutation function but we’re not allowed?

I strongly disagree with this sentiment. I agree that the compiler can
figure it out without us in many cases but I appreciate knowing
*explicitly* which parts of an API will mutate a value. It is helpful for
both the vendor and consumer of the API to require that keyword.

_______________________________________________

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


(Lino Rosa) #19

"1) Its not true. Its just about the reassignment. But for value-types in

automatic the process of copy-change and assign."

I understand that, but semantically it sure looks like it's true. It's an
implementation detail, all about the copy-on-write optimization right? Why
should the developer have to know about that?

"2) because only value types need this keyword"
"3) what's the problem here?"

Consistency. Makes the language harder to explain. To me the `mutating`
keyword should either be used in classes as well or not used at all. Both
would simplify things. But this is running off-topic from the original post
though.

"Can you elaborate this? Does not appear a real world problem."

Not a specific example, but every line like `something.a = "anotherValue"`
might or might not be relying on value semantics. After refactoring, the
developer would have no choice but to read every line with `something` and
judge whether value semantics was assumed or it was irrelevant. Really
error prone. Any mistake would result in unintended reference sharing, race
conditions etc. The actual bug might surface far from the originating issue.

"hu? Just check if the type is a struct or a enum! So will be a value

type. Whats the problem here?"

Of course, but you'd have to pause reading and jump to the definition each
time. And keep two mental models when structures and classes are used
together.

"No, the whole point of structs are not to be used in small and simple

cases, not on Swift, in swift um Swift are first class citizen and can be
use for complex data structure, like Array and Strings. You can make a
private shared buffer behind the scenes."

It does certainly seem to be this way in practice. It was the impression I
got from Swift's official docs: "*The structure’s primary purpose is to
encapsulate a few relatively simple data values.". *But now I realize it
talks about other possible use cases.

"Try this one: https://developer.apple.com/videos/play/wwdc2015-408/ ( Protocol-Oriented

Programming in Swift )"

I enjoyed this one, but it's about inheritance vs. protocols. He changes
classes to structures because he thinks it fits the model but he could have
kept classes and still proved his point that protocols are more powerful
and flexible.

I called my attention though, at around 25:20m he shows
`diagram.elements.append(diagram)` and says:* "**Now, it took me a second
to realize why Drawing wasn't going into an infinite recursion at this
point"*. That's kind of my point, these little surprises sprinkled around
the code.

Brent Royal-Gordon:

"In a regular method, `self` is a regular (constant) parameter, but in a

`mutating` method, `self` is `inout` so that it can be mutated and those
mutations will reach the caller's copy of the instance. There's no need for
an `inout` `self` on reference types, because the mutations are performed
on the shared instance which both the caller and callee have a reference
to, so `mutating` only really makes sense for value types."

But the `mutating` keyword isn't really needed to make `self` work this way
for structures. It's actually not strictly needed at all. Another thing the
`mutating` keyword "allows" is for the method to be able to reassign
properties. I was advocating that `mutating` had only that meaning in order
to be more consistent. Then it would be equally useful for classes to make
APIs more clear with respect to mutation.

···

On Fri, Dec 25, 2015 at 7:16 PM Brent Royal-Gordon <brent@architechies.com> wrote:

> However I could probably still agree with you if mutating was also used
in classes. What's the point of having it only on structures?

In a regular method, `self` is a regular (constant) parameter, but in a
`mutating` method, `self` is `inout` so that it can be mutated and those
mutations will reach the caller's copy of the instance. There's no need for
an `inout` `self` on reference types, because the mutations are performed
on the shared instance which both the caller and callee have a reference
to, so `mutating` only really makes sense for value types.

--
Brent Royal-Gordon
Architechies


(Austin Zheng) #20

Given that the Swift team has already said they aren't going to change the programming model, I don't think further conversation belongs on swift-evolution, to be honest.

Austin

···

On Dec 26, 2015, at 8:50 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

If you're serious about your proposal, you need to come up with a realistic plan for phasing out the current struct semantics for everyone, in every use case that they have.

Félix

Le 26 déc. 2015 à 11:14:44, Lino Rosa via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

> "1) Its not true. Its just about the reassignment. But for value-types in automatic the process of copy-change and assign."

I understand that, but semantically it sure looks like it's true. It's an implementation detail, all about the copy-on-write optimization right? Why should the developer have to know about that?

> "2) because only value types need this keyword"
> "3) what's the problem here?"

Consistency. Makes the language harder to explain. To me the `mutating` keyword should either be used in classes as well or not used at all. Both would simplify things. But this is running off-topic from the original post though.

> "Can you elaborate this? Does not appear a real world problem."

Not a specific example, but every line like `something.a = "anotherValue"` might or might not be relying on value semantics. After refactoring, the developer would have no choice but to read every line with `something` and judge whether value semantics was assumed or it was irrelevant. Really error prone. Any mistake would result in unintended reference sharing, race conditions etc. The actual bug might surface far from the originating issue.

> "hu? Just check if the type is a struct or a enum! So will be a value type. Whats the problem here?"

Of course, but you'd have to pause reading and jump to the definition each time. And keep two mental models when structures and classes are used together.

> "No, the whole point of structs are not to be used in small and simple cases, not on Swift, in swift um Swift are first class citizen and can be use for complex data structure, like Array and Strings. You can make a private shared buffer behind the scenes."

It does certainly seem to be this way in practice. It was the impression I got from Swift's official docs: "The structure’s primary purpose is to encapsulate a few relatively simple data values.". But now I realize it talks about other possible use cases.

> "Try this one: https://developer.apple.com/videos/play/wwdc2015-408/ ( Protocol-Oriented Programming in Swift )"

I enjoyed this one, but it's about inheritance vs. protocols. He changes classes to structures because he thinks it fits the model but he could have kept classes and still proved his point that protocols are more powerful and flexible.

I called my attention though, at around 25:20m he shows `diagram.elements.append(diagram)` and says: "Now, it took me a second to realize why Drawing wasn't going into an infinite recursion at this point". That's kind of my point, these little surprises sprinkled around the code.

Brent Royal-Gordon:

> "In a regular method, `self` is a regular (constant) parameter, but in a `mutating` method, `self` is `inout` so that it can be mutated and those mutations will reach the caller's copy of the instance. There's no need for an `inout` `self` on reference types, because the mutations are performed on the shared instance which both the caller and callee have a reference to, so `mutating` only really makes sense for value types."

But the `mutating` keyword isn't really needed to make `self` work this way for structures. It's actually not strictly needed at all. Another thing the `mutating` keyword "allows" is for the method to be able to reassign properties. I was advocating that `mutating` had only that meaning in order to be more consistent. Then it would be equally useful for classes to make APIs more clear with respect to mutation.

On Fri, Dec 25, 2015 at 7:16 PM Brent Royal-Gordon <brent@architechies.com <mailto:brent@architechies.com>> wrote:
> However I could probably still agree with you if mutating was also used in classes. What's the point of having it only on structures?

In a regular method, `self` is a regular (constant) parameter, but in a `mutating` method, `self` is `inout` so that it can be mutated and those mutations will reach the caller's copy of the instance. There's no need for an `inout` `self` on reference types, because the mutations are performed on the shared instance which both the caller and callee have a reference to, so `mutating` only really makes sense for value types.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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