Eugine Savin 4 Posted February 1, 2019 (edited) Simple question, why "Multiply" operator works, and "Equal" does not. compiler give error "[dcc32 Error] Project1.dpr(33): E2015 Operator not applicable to this operand type" program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TMyRecord2 = record public class operator Equal(const a: TMyRecord2; const b: array of Integer): boolean; class operator Multiply(const a: TMyRecord2; const b: array of Integer): TMyRecord2; end; class operator TMyRecord2.Equal(const a: TMyRecord2; const b: array of Integer): boolean; begin Result := True; end; class operator TMyRecord2.Multiply(const a: TMyRecord2; const b: array of Integer): TMyRecord2; begin Result := a; end; var b: boolean; r: TMyRecord2; begin try r := r * [10]; // this line is compiled b := r = [10]; // this line is not compiled except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. Edited February 1, 2019 by Eugine Savin 1 Share this post Link to post
Uwe Raabe 2055 Posted February 1, 2019 Probably because in the second case "[10]" is seen as a set constant by the compiler. It works if you declare a variable with a proper type: var b: boolean; a: array of Integer; r: TMyRecord2; begin try a := [10]; r := r * a; // this line is compiled b := r = a; // this line is not compiled except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. 1 Share this post Link to post
Eugine Savin 4 Posted February 1, 2019 (edited) 44 minutes ago, Uwe Raabe said: because in the second case "[10]" is seen as a set constant by the compiler Well, where is not "set of Integer", but code var i: Integer; begin i := 10; b := r = [i]; end is not compiled Edited February 1, 2019 by Eugine Savin typo Share this post Link to post
Eugine Savin 4 Posted February 1, 2019 (edited) And main question, why r := r * [10] // here [10] is array and b := r = [10] // here [10] is set what's difference ?? Edited February 1, 2019 by Eugine Savin Share this post Link to post
Uwe Raabe 2055 Posted February 1, 2019 In Delphi a set is denoted with square brackets. Unfortunately a constant array is also denoted with square brackets. I have to admit that I am not happy with this language design decision either. The term [10] as well as (i being an integer) can be both a set or array constant. There is no rule for the compiler to choose one or another. There are scenarios where the compiler chooses different than the developer intended. If you feel that the compiler is doing wrong here, please open a bug report with this example. Share this post Link to post
Rudy Velthuis 91 Posted February 1, 2019 (edited) 3 hours ago, Uwe Raabe said: In Delphi a set is denoted with square brackets. Unfortunately a constant array is also denoted with square brackets. I have to admit that I am not happy with this language design decision either. The term [10] as well as (i being an integer) can be both a set or array constant. There is no rule for the compiler to choose one or another. There are scenarios where the compiler chooses different than the developer intended. If you feel that the compiler is doing wrong here, please open a bug report with this example. I fully agree. It is never a good idea to give overridden operators variant open array parameters. You should have two (or sometimes one) single operands, not arrays. If you want to pass arrays, use functions. Edited February 1, 2019 by Rudy Velthuis Share this post Link to post
David Heffernan 2345 Posted February 2, 2019 10 hours ago, Rudy Velthuis said: I fully agree. It is never a good idea to give overridden operators variant open array parameters. You should have two (or sometimes one) single operands, not arrays. If you want to pass arrays, use functions. Operators are functions. There are certainly times when it might be useful to use arrays as operator arguments. I regret that the language designers have allowed literals to have meaning determined by context in various places. When there is insufficient context, as is inevitably the case on occasion, these kind of problems arise. 1 Share this post Link to post
Kryvich 165 Posted February 2, 2019 (edited) To tell the compiler the type of operand, I can advise the following: Replace array of Integer with TArray<Integer>. (In 10.3 Rio it is the same type.) Create a helper function: function AsArray(const [ref] Arr: TArray<Integer>): TArray<Integer>; inline; begin Result := Arr; end; ... b := r = AsArray([10]); // It compiles Edited February 2, 2019 by Kryvich Share this post Link to post
Rudy Velthuis 91 Posted February 2, 2019 2 hours ago, David Heffernan said: Operators are functions. There are certainly times when it might be useful to use arrays as operator arguments. But not open array arguments, IMO. Somehow that is against the idea of operators. It feels wrong. But that is my personal opinion. Share this post Link to post
Eugine Savin 4 Posted February 2, 2019 1 minute ago, Rudy Velthuis said: But not open array arguments, IMO What's problems with open arrays ? Anyway if I replace "array of Integer" by "TArray<Double>" r * [10.0] - compiled, but r = [10.0] is not ( E2001 Ordinal type required) // qc link https://quality.embarcadero.com/browse/RSP-23498 Share this post Link to post
Rudy Velthuis 91 Posted February 2, 2019 (edited) 13 minutes ago, Eugine Savin said: What's problems with open arrays ? Anyway if I replace "array of Integer" by "TArray<Double>" r * [10.0] - compiled, but r = [10.0] is not ( E2001 Ordinal type required) // qc link https://quality.embarcadero.com/browse/RSP-23498 I'm not quite sure if you are confusing open array parameters and dynamic arrays. They look alike, but are not the same thing. Your TArray<Double> is not an "open array", it is a dynamic array. I meant open array parameters. IMO, it doesn't make sense to give operators open array parameters. That would be like giving them three operands, e.g.: class operator Divide(const a, b: MyFloat; rounding: MyRoundingMode); It is obvious that that doesn't fit in the scheme x := operand1 / operand2; In the same way, open array parameters do not fit in there, IMO. Dynamic arrays do, of course, but I didn't mean those. Take a look at the concatenation of dynarrays: b := b + [4, 5, 6]; but those are not open array parameters. FWIW, it is QP, not QC anymore. Edited February 2, 2019 by Rudy Velthuis Share this post Link to post
Rudy Velthuis 91 Posted February 2, 2019 (edited) 21 minutes ago, Eugine Savin said: r = [10.0] Bad syntax, unless you mean to use them as default parameter. But default parameters don't match the notion of a dyadic operator either. It doesn't make a lot of sense to write: x := a +; where the second operand is a default value. In other words: there are, IMO, some things that should not be used with operators that are fine with normal functions: open array parameters and default parameters are two of them. Operators may be functions, but they have special semantics and not everything is allowed. IMO, open array parameters and default parameters should be among the features not allowed for operators either. Edited February 2, 2019 by Rudy Velthuis Share this post Link to post
Eugine Savin 4 Posted February 2, 2019 1 minute ago, Rudy Velthuis said: it doesn't make sense to give operators open array parameters. TMyArray = record .. end; const Arr1: array[0..1] of Integer = (..) const Arr2: array[0..2] of Integer = (..) var MyArray: TMyArray .. I wanna have ability to compare if (MyArray == Arr1) or (MyArray = Arr2).. How can I get it without open arrays as operator parameters ? Share this post Link to post
Rudy Velthuis 91 Posted February 2, 2019 (edited) 15 minutes ago, Eugine Savin said: TMyArray = record .. end; const Arr1: array[0..1] of Integer = (..) const Arr2: array[0..2] of Integer = (..) var MyArray: TMyArray .. I wanna have ability to compare if (MyArray == Arr1) or (MyArray = Arr2).. How can I get it without open arrays as operator parameters ? Having dynamic array parameters in an operator declaration is fine. Having open array parameters is not, IMO. In your case, simply do: function EqualArrays(const A: TMyArray; B: array of Integer): Boolean; And don't use operators. Hmmm... I see you use == C-like syntax. How would you do this in, say, C++? In C++, for an open array, you would have to pass a third parameter for the length of the static array, but how would you pass that? I doubt that the syntax allows it. I am pretty sure you would have to use... a plain function (or perhaps some template magic, but we don't have that in Delphi). Edited February 2, 2019 by Rudy Velthuis Share this post Link to post
Eugine Savin 4 Posted February 2, 2019 1 minute ago, Rudy Velthuis said: How would you do this in, say, C++? In C++ there is not differences between functions and overloaded operators. struct MyArray { public: template <std::size_t N> bool operator==(int (&rhs)[N]) { std::cout << N << '\n'; return true; } }; int main() { // your code goes here int arr1 [1] = {0}; int arr2 [2] = {0, 0}; MyArray myArr; if (myArr == arr1 && myArr == arr2) {} return 0; } 20 minutes ago, Rudy Velthuis said: And don't use operators. Can you explain why you allow operators with dyn arrays, and do not allow ones with open arrays ? Share this post Link to post
Rudy Velthuis 91 Posted February 2, 2019 (edited) 38 minutes ago, Eugine Savin said: In C++ there is not differences between functions and overloaded operators. struct MyArray { public: template <std::size_t N> bool operator==(int (&rhs)[N]) { std::cout << N << '\n'; return true; } }; int main() { // your code goes here int arr1 [1] = {0}; int arr2 [2] = {0, 0}; MyArray myArr; if (myArr == arr1 && myArr == arr2) {} return 0; } Can you explain why you allow operators with dyn arrays, and do not allow ones with open arrays ? First: I don't "allow" anything. But I think it doesn't make sense, in Delphi. As I said, it is possible with templates, because these can have value parameters like std::size_t N too. But that would still preclude dynamic arrays too, or their C++ equivalents. I do notice that that creates TWO overloaded operators: one for single-element static arrays, and one for two-element static arrays. In other words, it has two types. In Delphi, you can do that too, with overloading, but then you would have to create a type and an overload for every size. In other words: in Delphi, that doesn't make sense. Yes, it would be nice in your simple example, but if you have an open array parameter, it must accept dynarrays as well as static arrays of any size, and it must accept open array constructors (like a function Func([7, 8 9])). How would you do that, syntactically? Just like it doesn't make sense to give a dyadic operator like = or / a third operand, an open array constructor doesn't make sense either. A dynamic array is different. It is a single item, a single type. You could also have a single statci array type. Or several. See above. Can you explain why you can't use a function? Edited February 2, 2019 by Rudy Velthuis Share this post Link to post
David Heffernan 2345 Posted February 2, 2019 2 hours ago, Rudy Velthuis said: But not open array arguments, IMO. Somehow that is against the idea of operators. It feels wrong. But that is my personal opinion. It feels wrong isn't much of an argument. If open array arguments are fine for functions why not for operators, which are just functions with syntactic sugar. Can you explain your objection with reason, rather than relying on what it feels like. And surely you understand why operators are often preferred to functions. Share this post Link to post
Kryvich 165 Posted February 2, 2019 (edited) @Eugine Savin Is it possible to rewrite your C++ snippet as: MyArray myArr; if (myArr == {0} && myArr == {0, 0}) {} As I understand you need to inline array constants to the Delphi expressions. Edited February 2, 2019 by Kryvich Share this post Link to post
Rudy Velthuis 91 Posted February 2, 2019 (edited) 9 hours ago, David Heffernan said: It feels wrong isn't much of an argument. If open array arguments are fine for functions why not for operators, which are just functions with syntactic sugar. There are other things that are not fine for operators. One of the parameters or the return value must be of the type of record; there can only be one or two parameters, depending on the operator; etc. So they are not just normal functions. As I said, IMO it is against the notion of using operators to have open array parameters, i.e. against the semantics, not necessarily against the technical possibilities. As I said, I can't really put my finger on it yet, but it simply feels wrong. Not everything that compiles (i.e. that the compiler allows) is the right thing to do. > And surely you understand why operators are often preferred to functions. Sure. That doesn't mean they are the best thing to use in all circumstances. Edited February 2, 2019 by Rudy Velthuis Share this post Link to post
David Heffernan 2345 Posted February 3, 2019 11 hours ago, Rudy Velthuis said: Sure. That doesn't mean they are the best thing to use in all circumstances. In this circumstance, for testing equality, why do you believe that a function is better than an operator? Share this post Link to post
David Heffernan 2345 Posted February 3, 2019 11 hours ago, Rudy Velthuis said: So they are not just normal functions. Methods aren't normal functions by that argument, so why are open array parameters fine for them? The real problem here is the decision to allow literals to have type determined by context. So [10] is either a set or an array. That is incompatible with other language features. Like method and operator overloading. There is a good reason why other languages don't attempt to infer type of literals from context. Share this post Link to post
Rudy Velthuis 91 Posted February 23, 2019 (edited) On 2/3/2019 at 12:34 PM, David Heffernan said: Methods aren't normal functions by that argument, so why are open array parameters fine for them? The real problem here is the decision to allow literals to have type determined by context. So [10] is either a set or an array. That is incompatible with other language features. Like method and operator overloading. There is a good reason why other languages don't attempt to infer type of literals from context. They are not normal static class methods either. There are restrictions and IMO, open array parameters should be among those restrictions. Otherwise, they are different too: e.g. certain operators can be overloaded by return type. The way they are called is especially different. They are not called with parameter lists, and to have open array constructors, you need parameter lists. But even if open array parameters are allowed for operators, they are simply a stupid idea. Edited February 23, 2019 by Rudy Velthuis Share this post Link to post
David Heffernan 2345 Posted February 24, 2019 13 hours ago, Rudy Velthuis said: But even if open array parameters are allowed for operators, they are simply a stupid idea. It doesn't seem to me to be stupid to want to use arrays and operators together. Share this post Link to post
Rudy Velthuis 91 Posted February 24, 2019 12 hours ago, David Heffernan said: It doesn't seem to me to be stupid to want to use arrays and operators together. Nothing wrong with arrays and operator, but everything with open array parameters on operators. Operators should have one or two parameters, depending on the type of operator, and not ranges of operands. Share this post Link to post
David Heffernan 2345 Posted February 24, 2019 1 hour ago, Rudy Velthuis said: Nothing wrong with arrays and operator, but everything with open array parameters on operators. Operators should have one or two parameters, depending on the type of operator, and not ranges of operands. 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. Share this post Link to post