[swift-users] Are value semantics really appropriate in a diagramming app?

Dave Abrahams dabrahams at apple.com
Tue Aug 2 16:59:27 CDT 2016


on Tue Aug 02 2016, Rick Mann <rmann-AT-latencyzero.com> wrote:

>> On Aug 2, 2016, at 13:07 , Dave Abrahams via swift-users <swift-users at swift.org> wrote:
>> 
>> 
>> on Mon Aug 01 2016, Rick Mann <swift-users-AT-swift.org> wrote:
>> 
>
>>>> On Aug 1, 2016, at 19:18 , Jack Lawrence <jackl at apple.com> wrote:
>>>> 
>>>> Jens: Why? There are significant benefits to value semantics for
>>>> this type of problem, for the reasons laid out in the WWDC
>>>> videos. It would be helpful to know why you disagree in this
>>>> case—maybe there are solutions to the issues you’re thinking of.
>>>> 
>>>> Rick: I’d think that value semantics would be the right choice
>>>> here. When you do a mutation, you would copy the state of the entire
>>>> diagram. It should be efficient via COW, but if not you can
>>>> implement you own more fine-grained COW types with
>>>> isUniquelyReferenced(). This would allow you to easily support
>>>> things like undo.
>>> 
>>> The more I consider this, the more I think value semantics won't work
>>> for me. I think, to take advantage of the easy undo feature, my entire
>>> model *must* be implemented with value semantics.
>> 
>> That certainly helps.  You could introduce an explicit copy operation
>> to get around the use of classes, but that can get very messy.
>> 
>>> But my model has implicit reference semantics: multiple instances of a
>>> part can share a PartDefinition; it is intended that if the
>>> PartDefinition changes, all the referencing instances get the
>>> change. 
>> 
>> That is definitely a reference.  However, there are lots of ways to
>> represent references such that the entire model still has value
>> semantics.  Reference semantics, in the broadest sense, are everywhere:
>> as soon as you have an array and an integer, you have reference
>> semantics.  The problem with using classes is that they introduce
>> reference semantics *implicitly* and *prolifically*.
>> 
>> So, for example, if you are implementing a model and you want to
>> represent a selection as a separate data structure, then you'll need to
>> give every selectable element some kind of id, so you can store the ids
>> there. One way to do that is to store all your elements in an array in
>> your model, and use the index into the array as the id.  Then when one
>> element needs to refer to another element, it stores the ID of that
>> element.
>> 
>> [Aside: one of the simplest and most efficient representations of a
>> generalized graph structure is `[[Int]]`, which has value semantics.
>> Each element of the outer array corresponds to a vertex, and each
>> element an inner array represents the target of that vertex's outgoing
>> edges]
>> 
>> The most obvious thing you don't get from this kind of arrangement is
>> automatic lifetime management: an element doesn't disappear just because
>> you've stopped referring to it.  Whether that's appropriate for your
>> application or not is a question for you to answer.  
>> 
>> You can selectively recreate as much of the implicit behavior of classes
>> as you like, e.g. storing reference counts to recreate automatic
>> lifetime management and/or threading a free list through the array to
>> maintain ID stability, but of course at some point it becomes silly.
>> 
>> Where your particular application falls in this spectrum is for you to
>> say.  The fact that there's a component of reference semantics in your
>> model doesn't mean you can't use value types, and the fact that using
>> value types has some awesome benefits doesn't mean you can't use
>> classes.  Weigh the tradeoffs and make an informed choice.
>> 
>>> There are additional situations in which reference semantics are at
>>> play, as well: a PartDefinition can have one or more labels, but each
>>> instance can specify the relative location of the label for that
>>> instance. So, there is struct that contains a position and a reference
>>> to the label in the PartDefinition. But if the contents of the label
>>> changes, all the instances need to see that change.
>>> 
>>> I don't think I get to take advantage of value semantics, and it makes
>>> me wonder if any typical, non-trivial model's object graph really has
>>> no reference semantics.
>> 
>> Some do, but many-to-one relationships are an important concept, and
>> many applications need to represent them somehow.  I've personally found
>> that most such relationships are best expressed explicitly, which allows
>> me to preserve value semantics of the whole system. YMMV, of course.
>
> Hmm. Seems there's a need in the language for expressing exactly this
> kind of thing: explicit reference semantics. 

That's called “class.” ;-) But more seriously, if you have ideas, I'm
all ears (on the -evolution list, of course).

> I sure don't want to manage that all on my own.

It's not that big a deal; you manage it all on your own every time you
use an array, dictionary, or set, with indices or keys playing the role
of references.

Cheers,

-- 
-Dave


More information about the swift-users mailing list