Jump to content
Eugine Savin

operator overloding Equal vs Multiply

Recommended Posts

On 2/1/2019 at 6:06 PM, Uwe Raabe said:

Probably because in the second case "[10]" is seen as a set constant by the compiler.

This clearly seems to be a glitch in the compiler when doing the operator/overload resolution where it does find a proper match for Equal/NotEqual (did not test all possible operator combinations but those two).

Share this post


Link to post
58 minutes ago, Stefan Glienke said:

This clearly seems to be a glitch in the compiler

I am inclined to see this as the compiler barfing at the language designer who came up with this ambiguous set/array thing in the first place.

  • Like 2

Share this post


Link to post
On 2/24/2019 at 10:06 PM, David Heffernan said:

Dude, an array doesn't have to mean a range of operands. An array can be viewed as a single thing.

 

Also, it's entirely possible to imagine useful operators with more than two operands. 

Duuude, an open array parameter is not one single thing, IMO. And the operators defined in Delphi only have one or two operands. Anything else makes no sense for those operators.

Share this post


Link to post
4 minutes ago, Rudy Velthuis said:

Duuude, an open array parameter is not one single thing, IMO. And the operators defined in Delphi only have one or two operands. Anything else makes no sense for those operators.

An array can be thought of as a single entity. Consider vector arithmetic. Take two vectors of length N and sum them. That's one operator, two operands, each operand a vector with N scalar components. 

 

My entire livelihood is based on such a form of mathematics. Are you saying I've been doing it wrong? 

Edited by David Heffernan
  • Like 2

Share this post


Link to post
On 2/25/2019 at 2:35 PM, Uwe Raabe said:

I am inclined to see this as the compiler barfing at the language designer who came up with this ambiguous set/array thing in the first place.

Well yes, the syntax overlap is unfortunate and very confusing. But sets exist much longer than dynarray constants or even much longer than open array constructors, so sets should always win, IMO. They could have used ([ and ]) or similar for open array parameters or even some kind of (alternative) function-like syntax.

Share this post


Link to post
4 hours ago, David Heffernan said:

An array can be thought of as a single entity. Consider vector arithmetic. Take two vectors of length N and sum them. That's one operator, two operands, each operand a vector with N scalar components. 

 

My entire livelihood is based on such a form of mathematics. Are you saying I've been doing it wrong? 

Sure, arrays/vectors/matrices/lists/tuples/etc. can be thought of as single entities and I fully agree that one can use operators to combine them too, or to map single operations to such structures (e.g. like numpy's "broadcasts":  myNewArray := myArray + 3;). But not open array parameters. They are parameters. Parameters belong in a parameter list, and operators do not have parameter lists. Well yes, they can have formal parameter lists when you declare their overloads, but not when they are used in infix or prefix notation. And that use is their sole raison d'être. After all, everything an operator does can be done with a plain function call too, like they do in Java; it just doesn't look so "natural".

 

So if I had designed operator overloading, I would not have allowed open array parameters or arrays of const for them, for (to me) obvious reasons. I would of course have allowed predefined array types, dynamic and static, and TArray<x>, and what not.

 

Edited by Rudy Velthuis

Share this post


Link to post
2 hours ago, Rudy Velthuis said:

Sure, arrays/vectors/matrices/lists/tuples/etc. can be thought of as single entities and I fully agree that one can use operators to combine them too, or to map single operations to such structures (e.g. like numpy's "broadcasts":  myNewArray := myArray + 3;). But not open array parameters. They are parameters. Parameters belong in a parameter list, and operators do not have parameter lists. Well yes, they can have formal parameter lists when you declare their overloads, but not when they are used in infix or prefix notation. And that use is their sole raison d'être. After all, everything an operator does can be done with a plain function call too, like they do in Java; it just doesn't look so "natural".

 

So if I had designed operator overloading, I would not have allowed open array parameters or arrays of const for them, for (to me) obvious reasons. I would of course have allowed predefined array types, dynamic and static, and TArray<x>, and what not.

 

It's almost as if you don't know what a vector is. 

Share this post


Link to post
4 hours ago, David Heffernan said:

It's almost as if you don't know what a vector is. 

I know what a vector is, in several meanings of the word, thanks, and I know how to use them, or calculate with them or what kind of operations on them make sense.

 

Not sure what that has to do with the fact that I think it is silly and stupid to declare open array parameters on overloaded operators. If you want to pass open array parameters to something, make that something a function, not an operator.

 

And note that I think there is nothing wrong with declaring static array types (including Euclidian vectors or transformation matrices) or dynamic array types as parameters for operators. It makes sense to add two vectors (Euclidian kind) or concatenate the C++ kind of vectors using a + operator. It also makes sense to multiply a vector (any kind, actually) with a scalar using a * operator. But operators and open array parameters are a bad match.

 

Again: this is fine:

class operator Multiply(Left: Double; const Right: TVector3): TVector3; // scales a plain static 3D vector
// or:
class operator Multiply(Left: Double; const Right: TArray<Double>): TArray<Double> // numpy-style "broadcast": each element of Right is multiplied by Left.

But this doesn't make any sense IMO:

class operator Multiply(const Left, Right: array of Double): TArray<Double>; // Convolution: Left[i] is multiplied with Right[i]

If you want that, then code it as:

class function Multiply(const Left, Right: array of Double): TArray<Double>; static;

And then you can call it like

Result := Multiply([1.0, 2.0, 3.0], [4.0, 5.0, 6.0]);

But this is (syntactical) nonsense, IMO:

Result := [1.0, 2.0, 3.0] * [4.0, 5.0, 6.0];

Because you can't or at least shouldn't be able to use open array constructors like that, outside a parameter list. And they could be confused with dynamic array constants and perhaps even with sets anyway. Pure nonsense to try that, IMO.

So if it compiles but doesn't work as expected, I am not surprised.

Edited by Rudy Velthuis

Share this post


Link to post
8 hours ago, Rudy Velthuis said:

I know what a vector is, in several meanings of the word, thanks, and I know how to use them, or calculate with them or what kind of operations on them make sense.

 

Not sure what that has to do with the fact that I think it is silly and stupid to declare open array parameters on overloaded operators. If you want to pass open array parameters to something, make that something a function, not an operator.

 

And note that I think there is nothing wrong with declaring static array types (including Euclidian vectors or transformation matrices) or dynamic array types as parameters for operators. It makes sense to add two vectors (Euclidian kind) or concatenate the C++ kind of vectors using a + operator. It also makes sense to multiply a vector (any kind, actually) with a scalar using a * operator. But operators and open array parameters are a bad match.

 

Again: this is fine:


class operator Multiply(Left: Double; const Right: TVector3): TVector3; // scales a plain static 3D vector
// or:
class operator Multiply(Left: Double; const Right: TArray<Double>): TArray<Double> // numpy-style "broadcast": each element of Right is multiplied by Left.

But this doesn't make any sense IMO:


class operator Multiply(const Left, Right: array of Double): TArray<Double>; // Convolution: Left[i] is multiplied with Right[i]

If you want that, then code it as:


class function Multiply(const Left, Right: array of Double): TArray<Double>; static;

And then you can call it like


Result := Multiply([1.0, 2.0, 3.0], [4.0, 5.0, 6.0]);

But this is (syntactical) nonsense, IMO:


Result := [1.0, 2.0, 3.0] * [4.0, 5.0, 6.0];

Because you can't or at least shouldn't be able to use open array constructors like that, outside a parameter list. And they could be confused with dynamic array constants and perhaps even with sets anyway. Pure nonsense to try that, IMO.

So if it compiles but doesn't work as expected, I am not surprised.

That's not nonsensical from the programmer's perspective. Only from the constraints of the language design. 

 

I'm coming at this with an open mind as to what a programmer would like to be able to do. You are tied down by the historical precedent of syntax.

 

The fact that [1,2] can be an open array constructor, a dynamic array, or a set, depending on context is the root of the problem. It is that poor design of the language that is at the root of this question. 

 

So I object to your defence of the language and assertions that what the programmer wants to do is nonsensical. 

 

I struggle to understand these two claims of yours:

 

1. A plain function is a better way to implement an equality test than an operator. In my view that is an indefensible claim. You have to use a plain function because the language syntax doesn't support an operator. But that doesn't make the operator undesirable. Just unachievable. 

2. An operand that is an array implies more than two operands. I can't work that out. That's why I though you don't know what a vector is. But you seem to have got past that in your last post where you happily use arrays as operands. 

Share this post


Link to post
6 hours ago, David Heffernan said:

The fact that [1,2] can be an open array constructor, a dynamic array, or a set, depending on context is the root of the problem.

Not for me.

 

Yes, it is what makes using this a problem, but that is not my objection against open array parameters. I would be against them if they had a different, unambiguous syntax too.

 

And yes, I think the syntax choices made in the past were somewhat unfortunate and I would have preferred less ambiguous solutions, but that is not why I am against open array parameters on operators. I think the notion of open array parameters, especially open array constructors should be resticted to proper parameter lists of a function, and should not be used in any way on operators.

 

And yes, I think that is nonsensical from the programmer's perspective. I don't care about the language designers or how they could solve their compiler problems, but I do care about the design of the language itself, from the perspective of a user of the language. Open array parameters should never have been allowed for operator overloads, IMO. I think I have already said why. They are just as silly as varargs in an operator overload in C++ (and you can't specify varargs in such an operator overload in C++). Actually, open array parameters are quite a lot like varargs in C++ (not technically, but semantically). For the same reasons, I don't think they should be allowed in Delphi, even if technically, it is possible.

Share this post


Link to post
9 minutes ago, Rudy Velthuis said:

Actually, open array parameters are quite a lot like varargs in C++

Time to stop digging.

Share this post


Link to post
5 hours ago, David Heffernan said:

Time to stop digging.

I have no idea what you mean, but I do think that this discussion is fruitless. You obviously have a different POV than I have.

Edited by Rudy Velthuis

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×