associated objects


(Jay) #1

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it
here.

The implementation isn't great, but it's a small and simple proof of
concept. I have further extended this (not in GH, but very simple and happy
to share if anyone cares) to add dynamic methods using closures onto
individual object instances. Useful for user interactions, or adding
'actions' to objects.

I'd like to propose that this or something similar be added to the standard
library. It could potentially even be added to AnyObject so that developers
can use it without having to declare an extension for whichever classes
they want to use it on.

As mentioned, this can easily be extended (either in the standard library
or by developers) to add closures dynamically to any object, or to any
class, which could serve as a useful way for those not concerned with type
safety and the like to get some dynamic behaviour in there in the shorter
term. With a little language support it could even be used to implement
stored properties in extensions very easily.

A better implementation would need some language changes - specifically
deinit hooks (has that ever been discussed?) because of the way weak
references are lazily zeroed. Another implementation improvement might
lazily add the dictionary to each object instead of storing it globally -
not sure if this would have ABI implications.

Interested in feedback and thoughts :slight_smile:


(Robert Widmann) #2

Have you got a significant use-case for this that absolutely can't be solved by extensions or subclassing?

This does have ABI impact but more concerning for me is the performance impact and that the existing API is not type safe.

Using associated objects in ObjC gets you read through the slowest possible deallocation paths and means the runtime is effectively tracking an extra table of pointer tables per object-with-associations. To make this kind of pattern type safe you would, for example, need to keep track metatype pointers too and use the dynamic cast machinery to check the type on retrieval.

~Robert Widmann

2016/09/28 11:26、Jay Abbott via swift-evolution <swift-evolution@swift.org> のメッセージ:

···

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it here.

The implementation isn't great, but it's a small and simple proof of concept. I have further extended this (not in GH, but very simple and happy to share if anyone cares) to add dynamic methods using closures onto individual object instances. Useful for user interactions, or adding 'actions' to objects.

I'd like to propose that this or something similar be added to the standard library. It could potentially even be added to AnyObject so that developers can use it without having to declare an extension for whichever classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library or by developers) to add closures dynamically to any object, or to any class, which could serve as a useful way for those not concerned with type safety and the like to get some dynamic behaviour in there in the shorter term. With a little language support it could even be used to implement stored properties in extensions very easily.

A better implementation would need some language changes - specifically deinit hooks (has that ever been discussed?) because of the way weak references are lazily zeroed. Another implementation improvement might lazily add the dictionary to each object instead of storing it globally - not sure if this would have ABI implications.

Interested in feedback and thoughts :slight_smile:
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Goffredo Marocchi) #3

Have you got a significant use-case for this that absolutely can't be solved by extensions or subclassing?

This does have ABI impact but more concerning for me is the performance impact and that the existing API is not type safe.

Using associated objects in ObjC gets you read through the slowest possible deallocation paths and means the runtime is effectively tracking an extra table of pointer tables per object-with-associations. To make this kind of pattern type safe you would, for example, need to keep track metatype pointers too and use the dynamic cast machinery to check the type on retrieval.

If observers, whose lifetime is longer than the the observed objects' one, were notified when the observed object is deallocated then I would agree with you about safety concerns trumping usability... but as it is right now a nice mechanism like KVO is made trickier to use than it should be without associated objects (KVO leakage is quite a scary concept :)).

···

Sent from my iPhone

On 28 Sep 2016, at 17:27, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

~Robert Widmann

2016/09/28 11:26、Jay Abbott via swift-evolution <swift-evolution@swift.org> のメッセージ:

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it here.

The implementation isn't great, but it's a small and simple proof of concept. I have further extended this (not in GH, but very simple and happy to share if anyone cares) to add dynamic methods using closures onto individual object instances. Useful for user interactions, or adding 'actions' to objects.

I'd like to propose that this or something similar be added to the standard library. It could potentially even be added to AnyObject so that developers can use it without having to declare an extension for whichever classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library or by developers) to add closures dynamically to any object, or to any class, which could serve as a useful way for those not concerned with type safety and the like to get some dynamic behaviour in there in the shorter term. With a little language support it could even be used to implement stored properties in extensions very easily.

A better implementation would need some language changes - specifically deinit hooks (has that ever been discussed?) because of the way weak references are lazily zeroed. Another implementation improvement might lazily add the dictionary to each object instead of storing it globally - not sure if this would have ABI implications.

Interested in feedback and thoughts :slight_smile:
_______________________________________________
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


(Robert Widmann) #4

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it here.

The implementation isn't great, but it's a small and simple proof of concept. I have further extended this (not in GH, but very simple and happy to share if anyone cares) to add dynamic methods using closures onto individual object instances. Useful for user interactions, or adding 'actions' to objects.

I'd like to propose that this or something similar be added to the standard library. It could potentially even be added to AnyObject so that developers can use it without having to declare an extension for whichever classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library or by developers) to add closures dynamically to any object, or to any class, which could serve as a useful way for those not concerned with type safety and the like to get some dynamic behaviour in there in the shorter term. With a little language support it could even be used to implement stored properties in extensions very easily.

I’m not convinced by this explanation. You haven’t shown me any cases where this feature is absolutely necessary, merely enumerated features. I’m aware of how associated objects work, I’m not aware of why they are particularly useful in Swift and I’d like to be given something to the contrary.

As for the point about dismissing type safety: There is no precedent in the language for type-unsafe operations to be exposed wholesale to the end user like this. At the very least you should tag the API as Unsafe Associated Objects and now you’re stuck explaining why you’d like to stick a completely unsafe feature into a language that touts “Safety by Default”. It feels like pining for the Objective-C days of old, and I happen to think that that’s fine, but we have to do better than ObjC, not have features for the sake of features.

A better implementation would need some language changes - specifically deinit hooks (has that ever been discussed?) because of the way weak references are lazily zeroed. Another implementation improvement might lazily add the dictionary to each object instead of storing it globally - not sure if this would have ABI implications.

That kind of implementation would be space-inefficient - all Swift classes now automatically incur an extra pointer-sized allocation per instance. It absolutely has ABI implications too because now we have to track an extra part of the header for an object and standardize on access patterns for the associated objects table.

···

On Sep 28, 2016, at 11:26 AM, Jay Abbott via swift-evolution <swift-evolution@swift.org> wrote:

Interested in feedback and thoughts :slight_smile:
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Brent Royal-Gordon) #5

Actually, a somewhat different (DispatchSpecificKey-style) design makes type safety pretty easy:

  import Cocoa
  
  let myValue = AssociatedValue(.strong, ofType: String.self, on: NSView.self)
  
  let view = NSView()
  myValue[view] = "Hello, world!"
  myValue[view]

Implementation here: <https://gist.github.com/brentdax/75bfd619379fea53d8ca8afaa16d95bb>

Nevertheless, I don't think this should be shipped in Swift; associated objects are as esoteric as they come.

···

On Sep 28, 2016, at 9:27 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

To make this kind of pattern type safe you would, for example, need to keep track metatype pointers too and use the dynamic cast machinery to check the type on retrieval.

--
Brent Royal-Gordon
Architechies


(Michael Gottesman) #6

Have you got a significant use-case for this that absolutely can't be solved by extensions or subclassing?

This does have ABI impact but more concerning for me is the performance impact and that the existing API is not type safe.

Using associated objects in ObjC gets you read through the slowest possible deallocation paths and means the runtime is effectively tracking an extra table of pointer tables per object-with-associations. To make this kind of pattern type safe you would, for example, need to keep track metatype pointers too and use the dynamic cast machinery to check the type on retrieval.

Also from an optimization perspective, it prevents any analysis of the side-effects of destructors and causes the optimizer to have to treat all operations that could trigger a deinit as potentially doing anything.

Given the pervasiveness of release operations, we really do not want such conservatism if we can avoid it. So you really need to balance the need for an associated object against creating a language default that is not an abstraction that one can not avoid in code that is performance sensitive.

Michael

···

On Sep 28, 2016, at 9:27 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

~Robert Widmann

2016/09/28 11:26、Jay Abbott via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ:

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it here.

The implementation isn't great, but it's a small and simple proof of concept. I have further extended this (not in GH, but very simple and happy to share if anyone cares) to add dynamic methods using closures onto individual object instances. Useful for user interactions, or adding 'actions' to objects.

I'd like to propose that this or something similar be added to the standard library. It could potentially even be added to AnyObject so that developers can use it without having to declare an extension for whichever classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library or by developers) to add closures dynamically to any object, or to any class, which could serve as a useful way for those not concerned with type safety and the like to get some dynamic behaviour in there in the shorter term. With a little language support it could even be used to implement stored properties in extensions very easily.

A better implementation would need some language changes - specifically deinit hooks (has that ever been discussed?) because of the way weak references are lazily zeroed. Another implementation improvement might lazily add the dictionary to each object instead of storing it globally - not sure if this would have ABI implications.

Interested in feedback and thoughts :slight_smile:
_______________________________________________
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


(Karl) #7

I think that being able to retroactively associate data with some other data is extremely important. It’s unfortunate that it can’t be made more optimal from an implementation perspective, but it simplifies so many problems were you would otherwise associate data by keeping parallel collections of indices or whatnot.

I would like it if extensibility was built-in to types in Swift; that their internal layout reserved a pointer at the end, which could point to a dictionary or some other data.

Really, when it comes to retroactive extensibility, it’s incredibly strange that you can add functions but not data. If we were inventing a language without caring about the implementation cost, we would be able to, obviously. I actually don’t think the cost is all that high, and perhaps there are ways that the compiler could still optimise it (perhaps assigning each value an index in an array, rather than a dictionary?).

If we actually want Swift to be this amazing programming language which can scale from scripting to systems programming, we definitely need a way to arbitrarily tag objects. Lots of people won’t use it, and that’s fine, but there are times when you really need it and in those cases you wish you were using a different language.

Karl

···

On 28 Sep 2016, at 17:26, Jay Abbott via swift-evolution <swift-evolution@swift.org> wrote:

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it here.

The implementation isn't great, but it's a small and simple proof of concept. I have further extended this (not in GH, but very simple and happy to share if anyone cares) to add dynamic methods using closures onto individual object instances. Useful for user interactions, or adding 'actions' to objects.

I'd like to propose that this or something similar be added to the standard library. It could potentially even be added to AnyObject so that developers can use it without having to declare an extension for whichever classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library or by developers) to add closures dynamically to any object, or to any class, which could serve as a useful way for those not concerned with type safety and the like to get some dynamic behaviour in there in the shorter term. With a little language support it could even be used to implement stored properties in extensions very easily.

A better implementation would need some language changes - specifically deinit hooks (has that ever been discussed?) because of the way weak references are lazily zeroed. Another implementation improvement might lazily add the dictionary to each object instead of storing it globally - not sure if this would have ABI implications.

Interested in feedback and thoughts :slight_smile:
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Jay) #8

Hey Robert,

Well the example I gave was stored properties in extensions - that is they
can be easily implemented as calculated properties that actually use
associated objects/values to store their value. The other one is
per-instance actions, programmers can dynamically add an action (closure)
to any instance (for example decide where it needs to be sent and add a
closure with the key "send"), then that action can be performed later by
retrieving whatever is in "send" and calling it - basically whenever
functionality rather than data needs to be moved around.

I agree it's not an efficient or type-safe system, but of course any
developer using it is doing so at run-time so they know there's no
type-checking going on and should take measures to ensure only the correct
types are put into any situation (or check it themselves). It *can* be
implemented without affecting the ABI - as my example code shows, I'm just
not sure if this is a good way to do it.

I'm not sure what you mean about obj-c associated objects having a slow
deallocation path, is there a learning-point from the obj-c implementation
that helps here? If so I don't know it :slight_smile: I don't think you would try to
make it type-safe as it's a dynamic feature and you'd expect the users to
do that themselves - sure there could be ways to use reflection to help
out, but is this necessary?

As noted in the README - deinit hooks would enable an implementation that
doesn't need to do the internal clean-up. So it works as-is, but could be
improved with some language features.

···

On Wed, 28 Sep 2016 at 19:46 Goffredo Marocchi <panajev@gmail.com> wrote:

Sent from my iPhone

On 28 Sep 2016, at 17:27, Robert Widmann via swift-evolution < > swift-evolution@swift.org> wrote:

Have you got a significant use-case for this that absolutely can't be
solved by extensions or subclassing?

This does have ABI impact but more concerning for me is the performance
impact and that the existing API is not type safe.

Using associated objects in ObjC gets you read through the slowest
possible deallocation paths and means the runtime is effectively tracking
an extra table of pointer tables per object-with-associations. To make
this kind of pattern type safe you would, for example, need to keep track
metatype pointers too and use the dynamic cast machinery to check the type
on retrieval.

If observers, whose lifetime is longer than the the observed objects' one,
were notified when the observed object is deallocated then I would agree
with you about safety concerns trumping usability... but as it is right now
a nice mechanism like KVO is made trickier to use than it should be without
associated objects (KVO leakage is quite a scary concept :)).

~Robert Widmann

2016/09/28 11:26、Jay Abbott via swift-evolution <swift-evolution@swift.org>
のメッセージ:

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it
here.

The implementation isn't great, but it's a small and simple proof of
concept. I have further extended this (not in GH, but very simple and happy
to share if anyone cares) to add dynamic methods using closures onto
individual object instances. Useful for user interactions, or adding
'actions' to objects.

I'd like to propose that this or something similar be added to the
standard library. It could potentially even be added to AnyObject so that
developers can use it without having to declare an extension for whichever
classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library
or by developers) to add closures dynamically to any object, or to any
class, which could serve as a useful way for those not concerned with type
safety and the like to get some dynamic behaviour in there in the shorter
term. With a little language support it could even be used to implement
stored properties in extensions very easily.

A better implementation would need some language changes - specifically
deinit hooks (has that ever been discussed?) because of the way weak
references are lazily zeroed. Another implementation improvement might
lazily add the dictionary to each object instead of storing it globally -
not sure if this would have ABI implications.

Interested in feedback and thoughts :slight_smile:

_______________________________________________
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


(Charles Constant) #9

-1 for me, but...

I’m aware of how associated objects work, I’m not aware of why they are

particularly useful in Swift

If stored properties in Extensions aren't useful, why would anything else
in an Extension be useful either? I gather there are reasons it is
impractical to implement them, but saying there's no benefit to them is
like arguing against allowing methods in Extensions, or computed
properties.

My own reason for wanting stored properties in Extensions, is that it would
allow me to organize my classes according to their features. I'm working on
drag and drop at the moment, and I would find it much less confusing in
future, if I could keep all the related properties and methods I'm creating
isolated in a single file. It would also allow me to reuse the same View in
other projects that don't require Drag and Drop *as is.* Otherwise, when I
reuse the class, I'll have to either carry along stored properties I don't
need, or carefully weed them out.

we have to do better than ObjC

That's the reason I'm against the proposal, too. If we allow stored
properties they should be first-class citizens (assuming that is
technically possible, I don't understand enough about how Frameworks
etc are compiled to know if it would cause issues). I already avoid
Associated Objects because I worry the additional complexity will make my
apps harder to debug if there are memory or performance issues, so the
thought of baking them into Swift doesn't really appeal to me.

···

On Wed, Sep 28, 2016 at 6:52 PM, Robert Widmann via swift-evolution < swift-evolution@swift.org> wrote:

On Sep 28, 2016, at 11:26 AM, Jay Abbott via swift-evolution < > swift-evolution@swift.org> wrote:

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it
here.

The implementation isn't great, but it's a small and simple proof of
concept. I have further extended this (not in GH, but very simple and happy
to share if anyone cares) to add dynamic methods using closures onto
individual object instances. Useful for user interactions, or adding
'actions' to objects.

I'd like to propose that this or something similar be added to the
standard library. It could potentially even be added to AnyObject so that
developers can use it without having to declare an extension for whichever
classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library
or by developers) to add closures dynamically to any object, or to any
class, which could serve as a useful way for those not concerned with type
safety and the like to get some dynamic behaviour in there in the shorter
term. With a little language support it could even be used to implement
stored properties in extensions very easily.

I’m not convinced by this explanation. You haven’t shown me any cases
where this feature is absolutely necessary, merely enumerated features.
I’m aware of how associated objects work, I’m not aware of why they are
particularly useful in Swift and I’d like to be given something to the
contrary.

As for the point about dismissing type safety: There is no precedent in
the language for type-unsafe operations to be exposed wholesale to the end
user like this. At the very least you should tag the API as Unsafe
Associated Objects and now you’re stuck explaining why you’d like to stick
a completely unsafe feature into a language that touts “Safety by
Default”. It feels like pining for the Objective-C days of old, and I
happen to think that that’s fine, but we have to do better than ObjC, not
have features for the sake of features.

A better implementation would need some language changes - specifically
deinit hooks (has that ever been discussed?) because of the way weak
references are lazily zeroed. Another implementation improvement might
lazily add the dictionary to each object instead of storing it globally -
not sure if this would have ABI implications.

That kind of implementation would be space-inefficient - all Swift classes
now automatically incur an extra pointer-sized allocation per instance. It
absolutely has ABI implications too because now we have to track an extra
part of the header for an object and standardize on access patterns for the
associated objects table.

Interested in feedback and thoughts :slight_smile:
_______________________________________________
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


(Jay) #10

Robert,

What it does is allow developers to extend the language to do things that
it doesn't support. Associated Objects is just a flexible way to allow
developers to do that, and that's how I used it in Objective-C, so that's
what I thought of in Swift when I found that "I want to do <x> but the
language doesn't support it". Maybe there's a completely different way to
achieve the same thing - but I just went with what I know.

I'm not trying to make Swift more like Obj-C - far from it - I want Swift
to ditch all the Obj-C related stuff and be its own thing. It frustrates me
to see bad patterns in UIKit (for example) being present in UIKit-for-Swift
(I understand why of course, but it's annoying still). Also things like the
CharacterSet discussion in the other thread - to me it seems like some of
the Objective-C-related implementation details of Swift libraries are
leaking out (the language itself doesn't seem to suffer from this though).

So it's difficult to come up with concrete examples of "things a developer
might want to do but the language doesn't support" because almost by
definition they are unforeseen. I can only enumerate the things I have
wanted to do in Obj-C and Swift and how I got around it.
- Dynamically add properties to a class (obc-c) / implement stored
properties (swift).
- Add per-instance methods at run-time.
- Perform a function when some other object is deallocated (haven't solved
this in Swift yet, but in obj-c associated object deallocation is
well-defined so I used that).
- Other unforeseen things...

So maybe Associated Objects isn't the answer and I should have stated the
problem better, instead of jumping to what I thought the answer might be...
the problem I want to solve is this:

As a developer I want to do <x> but the language doesn't support it... what
helpful thing *can* I use right now that allows me to achieve this? I
accept the disclaimer by ticking this box:
[ ] Yes, I understand that I'm not using Swift anymore, but some custom
run-time thing that I'm building myself on top of Swift, so if I want type
safety I have to implement it, if I want copy-on-write or other
optimisations, I have to implement it, and I understand that performance
might not be the best too.

If Swift can provide something to help developers go beyond the abilities
the current version, isn't that a good idea?

···

On Fri, 30 Sep 2016 at 07:13 Brent Royal-Gordon <brent@architechies.com> wrote:

> On Sep 28, 2016, at 9:27 AM, Robert Widmann via swift-evolution < > swift-evolution@swift.org> wrote:
>
> To make this kind of pattern type safe you would, for example, need to
keep track metatype pointers too and use the dynamic cast machinery to
check the type on retrieval.

Actually, a somewhat different (DispatchSpecificKey-style) design makes
type safety pretty easy:

        import Cocoa

        let myValue = AssociatedValue(.strong, ofType: String.self, on:
NSView.self)

        let view = NSView()
        myValue[view] = "Hello, world!"
        myValue[view]

Implementation here: <
https://gist.github.com/brentdax/75bfd619379fea53d8ca8afaa16d95bb>

Nevertheless, I don't think this should be shipped in Swift; associated
objects are as esoteric as they come.

--
Brent Royal-Gordon
Architechies


(Jay) #11

Hey Karl,

Regarding your comment "It’s unfortunate that it can’t be made more optimal
from an implementation perspective" - I think that it can be done in an
optimal way, just that the language devs are focusing on other things at
the moment. I replied to this thread earlier, changing the subject to
"stored properties in extensions" because that's actually what is wanted
(associated objects is just one way to achieve it). I have some more to add
to that thread so I will continue there.

···

On Sat, 8 Oct 2016 at 12:19 Karl <razielim@gmail.com> wrote:

On 28 Sep 2016, at 17:26, Jay Abbott via swift-evolution < > swift-evolution@swift.org> wrote:

I have implemented Associated Objects (and values) in pure swift here:
https://github.com/j-h-a/AssociatedObjects

The README is very short and straight-forward so I won't re-describe it
here.

The implementation isn't great, but it's a small and simple proof of
concept. I have further extended this (not in GH, but very simple and happy
to share if anyone cares) to add dynamic methods using closures onto
individual object instances. Useful for user interactions, or adding
'actions' to objects.

I'd like to propose that this or something similar be added to the
standard library. It could potentially even be added to AnyObject so that
developers can use it without having to declare an extension for whichever
classes they want to use it on.

As mentioned, this can easily be extended (either in the standard library
or by developers) to add closures dynamically to any object, or to any
class, which could serve as a useful way for those not concerned with type
safety and the like to get some dynamic behaviour in there in the shorter
term. With a little language support it could even be used to implement
stored properties in extensions very easily.

A better implementation would need some language changes - specifically
deinit hooks (has that ever been discussed?) because of the way weak
references are lazily zeroed. Another implementation improvement might
lazily add the dictionary to each object instead of storing it globally -
not sure if this would have ABI implications.

Interested in feedback and thoughts :slight_smile:

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

I think that being able to retroactively associate data with some other
data is extremely important. It’s unfortunate that it can’t be made more
optimal from an implementation perspective, but it simplifies so many
problems were you would otherwise associate data by keeping parallel
collections of indices or whatnot.

I would like it if extensibility was built-in to types in Swift; that
their internal layout reserved a pointer at the end, which could point to a
dictionary or some other data.

Really, when it comes to retroactive extensibility, it’s incredibly
strange that you can add functions but not data. If we were inventing a
language without caring about the implementation cost, we would be able to,
obviously. I actually don’t think the cost is all that high, and perhaps
there are ways that the compiler could still optimise it (perhaps assigning
each value an index in an array, rather than a dictionary?).

If we actually want Swift to be this amazing programming language which
can scale from scripting to systems programming, we definitely need a way
to arbitrarily tag objects. Lots of people won’t use it, and that’s fine,
but there are times when you really need it and in those cases you wish you
were using a different language.

Karl


(Robert Widmann) #12

Robert,

What it does is allow developers to extend the language to do things that it doesn't support. Associated Objects is just a flexible way to allow developers to do that, and that's how I used it in Objective-C, so that's what I thought of in Swift when I found that "I want to do <x> but the language doesn't support it". Maybe there's a completely different way to achieve the same thing - but I just went with what I know.

"I want to do <x> but the language doesn't support it” is the whole reason for this list! I want to know what “<x>” is in order to wrap my head around your proposal better. I’m not here to invalidate your work with a slew of criticisms, I’m just trying to understand your proposal by probing you about it.

So it's difficult to come up with concrete examples of "things a developer might want to do but the language doesn't support" because almost by definition they are unforeseen. I can only enumerate the things I have wanted to do in Obj-C and Swift and how I got around it.
- Dynamically add properties to a class (obc-c) / implement stored properties (swift).
- Add per-instance methods at run-time.
- Perform a function when some other object is deallocated (haven't solved this in Swift yet, but in obj-c associated object deallocation is well-defined so I used that).
- Other unforeseen things…

Again, these are features and I want motivations behind them. Why should you be able to dynamically add stored properties and methods to any Swift class? Why should you be able to observe deallocation if deallocation calls are not guaranteed (remember, Objective-C and Swift do not guarantee -dealloc/deinit calls in any order at any time - please don’t assume an RAII-like model because it will lead to memory leaks and malformed code).

I will say: Perhaps if you’re having trouble motivating the inclusion of this feature, you may want to step back and reevaluate its place in the language and why you wanted to write this library in the first place. Often times, I find that really helps get the creative juices flowing. Or, if I can’t come up with anything, it means I go back to step 1 and start over. Proposals can be as much a learning process for us as it is for you.

So maybe Associated Objects isn't the answer and I should have stated the problem better, instead of jumping to what I thought the answer might be... the problem I want to solve is this:

As a developer I want to do <x> but the language doesn't support it... what helpful thing *can* I use right now that allows me to achieve this? I accept the disclaimer by ticking this box:
[ ] Yes, I understand that I'm not using Swift anymore, but some custom run-time thing that I'm building myself on top of Swift, so if I want type safety I have to implement it, if I want copy-on-write or other optimisations, I have to implement it, and I understand that performance might not be the best too.

So from what I’ve gathered you’ve written a library to do this yourself. You have a vision for how you want to use this library. You think that vision is compatible with a language-level change. From my perspective, your job now is to articulate that vision and motivate it to this list. I don’t think associated objects and the other dynamic features you mention are fundamentally incompatible with Swift, I just think the design that I’ve seen so far may not be the best way of going about it and I’m voicing my concerns as much.

If Swift can provide something to help developers go beyond the abilities the current version, isn't that a good idea?

No one disputes this. We just want to see your rationale.

···

On Sep 30, 2016, at 9:40 AM, Jay Abbott <jay@abbott.me.uk> wrote:

On Fri, 30 Sep 2016 at 07:13 Brent Royal-Gordon <brent@architechies.com <mailto:brent@architechies.com>> wrote:
> On Sep 28, 2016, at 9:27 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> To make this kind of pattern type safe you would, for example, need to keep track metatype pointers too and use the dynamic cast machinery to check the type on retrieval.

Actually, a somewhat different (DispatchSpecificKey-style) design makes type safety pretty easy:

        import Cocoa

        let myValue = AssociatedValue(.strong, ofType: String.self, on: NSView.self)

        let view = NSView()
        myValue[view] = "Hello, world!"
        myValue[view]

Implementation here: <https://gist.github.com/brentdax/75bfd619379fea53d8ca8afaa16d95bb>

Nevertheless, I don't think this should be shipped in Swift; associated objects are as esoteric as they come.

--
Brent Royal-Gordon
Architechies


(Jay) #13

"I want to do <x> but the language doesn't support it” is the whole reason
for this list! I want to know what “<x>” is in order to wrap my head
around your proposal better. I’m not here to invalidate your work with a
slew of criticisms, I’m just trying to understand your proposal by probing
you about it.

I know, and appreciate this, thanks :slight_smile: I'm not easily offended and I prefer
to be wrong in a room full of smarter people than right (or think that I'm
right when maybe not) in a room full of not smarter people. But I do
struggle to articulate this without patronising everyone by explaining how
I think it is (in order to be corrected) all the time. Hope that even makes
sense!

Again, these are features and I want motivations behind them. *Why*
should you be able to dynamically add stored properties and methods to
*any* Swift class?

If I'm using an existing framework such as UIKit, and I want to add
something it doesn't support, like drag+drop to all UIViews for example,
then my implementation might want to use stored properties to help keep
track of drag+drop-related config and state (isDraggable, isDropTarget,
sourceView, etc.). This way I can extend UIView and use the stored
properties from my extension methods, while keeping all the functionality
of all its subclasses.

There's probably a much better way to express the above in the abstract -
sorry I suck at that :slight_smile:

*Why* should you be able to observe deallocation if deallocation calls are

not guaranteed (remember, Objective-C and Swift do not guarantee
-dealloc/deinit calls in any order at any time - please don’t assume an
RAII-like model because it will lead to memory leaks and malformed code).

It's not deallocation, but deinit that would be useful. My motivation in
Swift for wanting this was to get around lazy weak reference zeroing in my
associated objects implementation. If the object is deinited, you can't ask
it for an associated object, therefore its weak reference in my
implementation would never be accessed so it would hang around forever. I
got around that with a horrible clean-up hack that accesses the weak
references just to ensure they get zeroed, so I wanted non-lazy zeroing (or
a deinit hook).

I will say: Perhaps if you’re having trouble motivating the inclusion of

this feature, you may want to step back and reevaluate its place in the
language and why you wanted to write this library in the first place.
Often times, I find that really helps get the creative juices flowing. Or,
if I can’t come up with anything, it means I go back to step 1 and start
over. Proposals can be as much a learning process for us as it is for you.

I know exactly why I wanted associated objects - to implement a) stored
properties in extensions; and b) per-instance actions. If stored properties
were available in extensions then I would not need it at all: a) I would
already have it; b) I'd implement it using stored properties.

So from what I’ve gathered you’ve written a library to do this yourself.

You have a vision for how you want to use this library. You think that
vision is compatible with a language-level change. From my perspective,
your job now is to articulate that vision and motivate it to this list. I
don’t think associated objects and the other dynamic features you mention
are fundamentally incompatible with Swift, I just think the design that
I’ve seen so far may not be the best way of going about it and I’m voicing
my concerns as much.

I guess you're right - it's really stored properties in extensions that I
want... but actually - what's the difference? Aren't they basically the
same thing? :slight_smile:

J

···

On Fri, 30 Sep 2016 at 15:41 Robert Widmann <devteam.codafi@gmail.com> wrote: