Doing the above is a little tiresome when you have a few different operators, though you can reduce it with generics (which may come with some other costs). So a solution I thought would be nice would be to use an attribute that would generate the other corresponding function for you, like so:
So I implemented this because it seemed easy and something I would've liked before. But mainly this was to get my feet wet with the compiler.
But seeing how there is an implementation, I thought I'll post this to see if anyone would actually like this and if it's not too much complexity added for not much gain? FWIW though there isn't much complexity added since it mainly adds onto the pre-existing architecture.
Might this be cleaner as part of the operator declaration? That way you couldn't apply it to arbitrary functions. Otherwise yes, I've wanted the same thing.
Perhaps we don't need to synthesize a new function that does this, but just reorder the arguments during type checking instead if an operator is @commutative.
Commutative is definitely the most common such rule, but I'm a little wary of building up an axiom system one attribute at a time. I.e., I don't think we want to end up with:
It's probably worth holding off on adding such a feature until we have a more general need and syntax for it. On the other hand, commutative is the 80% case, so maybe it stands on its own. Personally, I haven't found writing both versions out to be onerous.
I have scrapped many a plan for lack of this functionality. I've had plenty of situations where related but not hierarchically related types can all end up embedded in a common type via operations. Implicit conversions would be another way to handle this, I think
Yes, that sounds like an all-around better solution.
What functionality do you see these attributes having? The only thing I can think of these doing is enforcing semantics. But this seems really implausible to me since we'd have to build some sort of model checker to verify them (which would be cool though).
Maybe this is generally a good idea, but your example doesn't look convincing to me: multiplying a vector by a scalar (i.e. double) makes sense, but multiplying a scalar by a vector looks a bit odd to me.
I checked your implementation. That was a big effort and ... quite a big code.
If both arguments have same type (eg Vector+Vector) @commutative is just unnecessary. For different types I don't see a big deal in swapping the arguments, as suggesed by Richard Wei, provided (as far as I can see) there aren't many examples of this kind
These types of axioms also license optimizations. If you know a relation R is symmetric, then a R b is equivalent to b R a, so you can combine two calls into one if both appear. If you know that it's transitive, then the compiler can eliminate a R c if the program has already computed a R b and b R c.
Just throwing an idea out there: what if instead of annotating specific operator functions as commutative, we utilize precedencegroups?
For example, perhaps MultiplicationPrecedence could be defined as
precedencegroup MultiplicationPrecedence {
...
associativity: left
commutative: true
}
With commutative: true, any operators (such as *) which use the MultiplicationPrecedence group would be treated as commutative.
Going back to the original example...
As @rxwei suggested, when one attempts to perform a Double * Vector operation, the compiler simply reorder the operator function arguments.
What I see as the main advantages of this approach are that
it utilizes a Swift feature that deals with operators already
it helps maintain the consistency of operators; just as we can assume that * will always have a higher precedence than +, with this system, we can always assume that * will be commutative, regardless of the context