was it possible to add operator func to Swift class subscript method
var x = ["dkfkd", "dkff"]
x[2] ??= "mmmm" // equal to x[2] = x[2] ?? "mmmm"
was it possible to add operator func to Swift class subscript method
var x = ["dkfkd", "dkff"]
x[2] ??= "mmmm" // equal to x[2] = x[2] ?? "mmmm"
If I may join the party :) Love the responses from rickster and Airspeed Velocity... extending sequence types and default value types ...
The way it is posed, the question essentially describes an ordered set behaviour (only, provided by the operator rather than the type). So we can play with that idea in some very straightforward ways:
We could, however, seek to preserve the syntactic direction Apple is taking with Swift and build on their
+=
array concatenation operator:However, this is not preserving the relative order of elements in
rhs
that are not inlhs
. To do this we could:Which can be used like so:
This isn’t related to the subscript operator, but more a question of how to define a
??=
operator. Which you can do, but it might not work quite the way you expect.Here’s a possible implementation:
This compiles, and works as you might be expecting:
It will also work in combination with subscripts:
I say this might not work completely as expected because of the types.
a ?? b
takes an optionala
, and if it’snil
, returns a default ofb
. However it returns a non-optional value. That’s kinda the point of??
.On the other hand,
??=
cannot do this. Because the left-hand side is already determined to be optional, and an assignment operator cannot change the type only the value. So while it will substitute the value inside the optional in the case ofnil
, it won’t change the type to be non-optional.PS the reason the
??=
function compiles at all is because non-optional values (i.e. what you will get back fromlhs ?? rhs
) are implicitly upgraded to optional values if necessary, hencelhs ?? rhs
, of typeT
, can be assigned tolhs
, which is of typeT?
.If you don't have a requirement that this "extending subscript" operation be on
Array
itself, you might find it more straightforward to create your own type that wraps anArray
(or other buffer) than to wedge this behavior into anArray
extension.First, you were probably just thinking about using
array[array.count] = item
as a synonym for appending, right? (Beyond that, it gets more complicated, as @AirspeedVelocity notes, because there's the question of what to put in between the existing array elements and the new item.) Here's a version that does just that:If you want to be able to create a sparse collection, where you can assign an element at any numeric index without having to fill in placeholder elements in between nonconsecutive indices... you don't actually want an
Array
— you want aDictionary
whose keys are integers. You can do that with just aDictionary
if you like:Or, if you want slightly more array-like semantics, you can create your own type that wraps a
Dictionary
(and adoptsArrayLiteralConvertible
, forwards subscript to the underlying dictionary, etc).Since @MartinR points out I’ve probably misintepreted the question, here’s an answer to the other possible interpretation – that you want a subscript that adds a value to a collection if it isn’t present.
You won’t be able to do this with an operator. And you also won’t be able to change the behaviour of the standard subscript operator on an existing collection. But you can add a new subscript operator, that takes a custom type. So you could try this:
The downside is arrays have to have values at every position, so you have to put this new value in every entry between the current last and the target subscript:
Works a lot better for dictionaries:
You could also do a version that took a default to pad the array, separate from the value to assign at the specific subscript:
This has the benefit of a sensible default for the subscript
get
, too:(You could even get fancy and do a version that took a closure for the default that mapped the index).