Confusion overloaded operator

As I progress through my small math library, I come across some aspects of the C # and .NET Framework that I find difficult to understand.

This time it is operator overload, and in particular, the term overload. Why is this called overload? Do all objects have an implementation of all operators by default? I.e:

public static object operator +(object o1, object o2) 

predetermined somewhere and somehow? If so, why, if I try o1 + o2 , do I get a compile-time error Operator '+' cannot be applied to operands of type 'object' and 'object' ? This would somehow mean that, by default, objects do not have predefined operators, so how then is the term overload?

I ask about this because in my math library that works with 3D geometry elements, I have the following structures: Vector and Point . Now, internally, I want to allow the following construct to create vectors:

 static Vector operator -(Point p1, Point p2) {...} 

Since this is not mathematically 100% correct, but very useful internally to reduce code clutter, I don’t want to publicly publish this statement, so my initial intention was to simply do:

 internal static Vector operator -(Point p1, Point p2) {...} 

Surprisingly (for me) I received the following compile-time error: User-defined operator 'Geometry.operator +(Geometry.Vector, Geometry.Vector)' must be declared static and public ".

Now this is the limitation that all operators should be publicly available, it seems to make some sense with the whole overloading aspect of the operators, but it seems that all this is contradictory:

  • Objects by default do not have predefined operators: I cannot execute object + object by default or myTpye + myType without explicitly defining the + operator in advance.
  • Defining operators are not described as creating an operator, it is described as overload, which somehow contradicts (me) with point 1.
  • You cannot limit the operator access modifier, they must be public , which does not make sense considering point 1. but the view makes sense, considering point 2.

Can someone explain the mess I'm making from all this in simple words?

+6
source share
3 answers

Why is this called overload?

It is called "overload" because it is overloaded. We “overload” a thing when we give two possible implementations for this thing, and then we must decide what to use (what is called overload resolution).

When we overload methods, we give two or more implementations of the method with the given name. When we overload operators, we provide two or more possible implementations for an operator with the given syntax. It is the same.

Make sure you do not confuse overloading with overriding. Overloading is simply the existence of two methods / statements with the same name / syntax in the same declaration space. Overriding deals with how the contents of a virtual method slot are populated at run time.

Do all objects have an implementation of all operators by default?

No.

Is public static object operator +(object o1, object o2) predefined somewhere and somehow?

No.

This would somehow mean that objects by default do not have predefined operators, so how then is the term overload?

I do not understand the question. Of course, C # has predefined operators.

I do not want to publicly publish this statement

Then do not use the operator; make a private, internal or secure method.

The design of C # is that the operator is always part of the total surface area. It is very confusing to have operators that matter, which depends on which scope of use the use is in. C # was carefully designed to be the language of the "pit of quality", where the choice of language designers forces you to refuse to write embarrassing, buggy, hard to access programs for refactoring. The requirement that user statements are public and static is one of those design subtle points.

(1) Objects do not have predefined operators by default

Of course they do it; There are hundreds of predefined operators on many objects. To add, for example, the following predefined overloads of the + operator exist:

 int + int uint + uint long + long ulong + ulong double + double float + float decimal + decimal enum + underlying (for any enum type) underlying + enum int? + int? uint? + uint? long? + long? ulong? + ulong? double? + double? float? + float? decimal? + decimal? enum? + underlying? underlying? + enum? string + string object + string string + object delegate + delegate (for any delegate type) 

Refer to the C # specification for a list of all the predefined overloads of all other operators.

Note that overload resolution for operators has two phases: first, overload resolution tries to find the user-defined overload that is the best; only if no suitable candidates are detected, are these predefined overloads taken into account by the resolution of the overload.

(2) The defining operators are not described as creating an operator, it is described as overload, which is somehow contradictory (to me) with point 1.

I don’t understand why you consider this inconsistent or, for that matter, what you consider inconsistent. The term "overload" is used sequentially to describe both operators and methods; in both cases, this means using the same syntax to denote two or more different things, and this ambiguity is then resolved using "overload resolution." The exact details of the method resolution algorithms and the overload algorithms are different, but they are the same in the general algorithm: first, a set of candidates is identified, then inapplicable candidates are deleted, then the survival algorithm eliminates the applicable candidates that are worse than the other, then the optimality algorithm determines the only best candidate that remains if there is one.

(3) You cannot restrict the operator access modifier, they must be publicly available, which does not make sense, given point 1. but the variety makes sense, given point 2.

I don’t understand which point (3) is connected with points (1) or (2) in general. The limitation that operators must be part of the public surface area is to prevent a confusing situation where you can add Fruit to Animal when you are inside the Apple class, but not when you are inside the Giraffe class.

Operators are declared inside a class or structure and therefore "belong" to the specified type, they do not float "belonging" to this type. So what do I overload exactly when I declare an operator in a class?

You overload the operator.

The fact that the same operator exists between ints does not mean that I overload anything, since this operator belongs to int. For me, this is the same as saying Foo.Hello() and Bar.Hello(string hello) are Hello overloads. They are not like they are declared in two different types. What is the difference with operators?

You accurately described the difference. Method overloading and overloading differ in many details.

If you want to accept the position that Foo.Hello() and Bar.Hello(string) are Hello overloads, this is not a common position, but it is logically consistent.

I got the impression that when overloaded you cannot change the access modifier.

Your impression is wrong; you cannot change access modifiers when overriding a virtual method. You confused this with overload.

(And I note that there is one scenario in which you need to change the access modifier when overriding the virtual method, can you determine what it is?)

I also got the impression that you cannot declare an operator from at least one of the operands of the type in which you declare the operator.

This is almost correct. The user operator must have an operand of type T , where T is a class or structure type, or T? if T is the type of structure.

So, how can the third class have access to this operator, and the other third class cannot, if it does not belong to the external assembly and the other does not? In this case, I do not find it confusing at all and even useful?

You incorrectly described my example, which could be more understandable. It's illegal:

 public class Fruit { protected static Shape operator +(Fruit f, Animal a) { ... } } 

Because it is strange:

 public class Apple : Fruit { ... Shape shape = this + giraffe; // Legal! } public class Giraffe : Animal { ... Shape shape = apple + this; // Illegal! } 

This is just one example. In general, it is strange to make the operator overload resolution dependent on the availability domain, therefore, the language developers have guaranteed that this will never happen if the user statements are public.

I just find overload confusing in the context of statements.

Many people do, including compilers. The user part of the specification specification is extremely difficult to analyze, and the Microsoft implementation is a rich source of compiler errors, many of which were my mistake.

I don’t understand why just declaring statements in a type should be described differently than describing the declaration of some other static method.

Well, different things are different; operators differ in many respects from methods, including their overload resolution algorithms.

I never liked that C # has overloaded operators. The C # function is a slightly improved version of the same function in C ++, but in both languages ​​this function, in my opinion, entails much higher costs than the corresponding advantages for users.

Thank goodness at least C # does not completely abuse the operator << way that idiomatic C ++ does, although it certainly abuses + and - for delegates.

+16
source
  • you cannot do object + object , because operators must be declared in the type of one of the operands; Point + Point must be declared in Point ; you cannot define object + object because you are not declaring object ; note that all objects have (at the language level, at least) the operators == / !=
  • The only important difference here is that you do not call it overriding - you should not be mistaken that they are somehow polymorphic - they are not; if you want to think of it as a “creation", that’s fine, but keep in mind that in non-trivial cases there may be multiple overlapping operators containing the same types, for example, with operators == / != , or where the operators inherited from a non-trivial hierarchy
  • this is what is; the specification states that they must be public , so either make them public or use methods of the non-operator internal
+2
source

You are probably confusing the term “overload” with the term “override”.

This is an example of an overload of the Foo method:

 public class Parent { public sealed void Foo(int n) { } } public class Child : Parent { public sealed void Foo(string s) { } } 

This is an example of overriding the Foo method:

 public class Parent { public virtual int Foo() { return 0; } } public class Child : Parent { public override int Foo() { return 1; } } 

As you can see, overloading is the addition of a new signature that will always be called regardless of the previous existing signature. The transformation involved providing a completely new implementation of the existing signature.

In this case, you might think that the + operator is just a different method (essentially, under a different syntax). If you provide a new implementation of the existing signature, say, the signature operator + (int a, int b) , then you would override this method. (Note that it is not possible to override an operator or any static method in C #.) What you do is overloading it by adding a new “signature” to the plus operator, which accepts a set of operands that did not previously exist for any other operator overload plus.

+2
source

Source: https://habr.com/ru/post/947544/


All Articles