F# Cast as Prefix Operator - casting

In F#, many infix operators can be made prefix operators:
a + b
(+) 1 a b
However, this doesn’t seem to be allowed for the upcast (or downcast) operators.
x is a UserPrincipal, which inherits from Principal
x :> Principal
(:>) x Principal
Why?

Probably because unlike other operators, the cast operators don't take two expressions as arguments; they take an expression and a type. So (:>) x would have to be "a function that takes a type", which is not a thing that exists in F#.

Related

C++ member access/indirection operator equivalence

I was looking at the C++ standard regarding member reference operators (the unary * dereferencing operator, the -> member accessor operator) as well as many other related questions:
C++ - Difference between (*). and ->?
ptr->hello(); /* VERSUS */ (*ptr).hello();
C++ pointers difference between * and ->
I saw that most answers stated that p->m is syntactic sugar for (*p).m as defined by the C++ Standard (5.2.5, paragraph 2):
The expression E1->E2 is converted to the equivalent form (*(E1)).E2
Many comments also noted that because operator* and operator-> are overloadable in classes, they should be overloaded uniformly to ensure consistent behavior.
These statements seem to contradict each other: if (as per the standard) E1->E2 is converted to the equivalent form (*(E1)).E2, then what would be the purpose of overloading operator-> (as is permitted by the standard)?
Simpler stated, are these two parts of the standard in conflict, or am I misunderstanding the Standard?
Does the E1->E2 equivalence transformation to (*(E1)).E2 apply to all complete types or only to built in ones?
The conversion from E1 -> E2 to (*(E1)).E2 only applies to raw pointer types. For class types, E1 -> E2 evaluates to (E1).operator->().E2, which potentially might recursively expand out even more copies of operator-> if the return type of operator-> is not itself a pointer type. You can see this by creating a type that supports operator* but not operator-> and trying to use the arrow operator on it; you'll get an error that operator-> is undefined.
As a follow-up, it's common to implement operator -> in terms of operator * in a way that makes the semantics of -> match the semantics for pointers. You often see things like this:
PointerType ClassType::operator-> () const {
return &**this;
}
This expression is interpreted as
&(*(*this)),
meaning "take this object (*this), dereference it (*(*this)), and get the address of what you find (&(*(*this)).)." Now, if you use the rule that E1 -> E2 should be equivalent to (*(E1)).E2, you can see that you end up getting something equivalent.

De Morgan's Law optimization with overloaded operators

Every programmer should know that:
(De Morgan's Laws)
Under some circumstances, in order to optimize the program, it may happen that compiler modifies (!p && !q) to (!(p || q)).
The two expressions are equivalent, and it makes no difference evaluating the first or the second.
But in C++ it is possible to overload operators, and the overloaded operator may not always respect this property. So transforming the code this way will actually modify the code.
Should the compiler use De Morgan's Laws when !, || and && are overloaded?
Note that:
Builtin operators && and || perform short-circuit evaluation (do not evaluate the second operand if the result is known after evaluating the first), but overloaded operators behave like regular function calls and always evaluate both operands.
...
Because the short-circuiting properties of operator&& and operator|| do not apply to overloads, and because types with boolean semantics are uncommon, only two standard library classes overload these operators ...
Source: http://en.cppreference.com/w/cpp/language/operator_logical
(emphasis mine)
And that:
If there is a user-written candidate with the same name
and parameter types as a built-in candidate operator function, the built-in operator function is hidden and
is not included in the set of candidate functions.
Source: n4431 13.6 Built-in operators [over.built] (emphasis mine)
To summarize: overloaded operators behave like regular, user-written functions.
NO, the compiler will not replace a call of a user-written function with a call of another user-written function.
Doing otherwise would potentially violate the "as if" rule.
I think that you have answered your own question: no, a compiler can not do this. Not only the operators can be overloaded, some can not be even defined. For example, you can have operator && and operator ! defined, and operator || not defined at all.
Note that there are many other laws that the compiler can not follow. For example, it can not change p||q to q||p, as well as x+y to y+x.
(All of the above applies to overloaded operators, as this is what the question asks for.)
No, in that case the transformation would be invalid. The permission to transform !p && !q into !(p || q) is implicit, by the as-if rule. The as-if rule allows any transformation that, roughly speaking, cannot be observed by a correct program. When overloaded operators are used and would detect the transformation, that automatically means the transformation is no longer allowed.
Overloaded operators per se are just syntactic sugar for function calls; the compiler itself is not allowed to make any assumption about the properties that may or may not hold for such calls. Optimizations that exploit properties of some specific operator (say, De Morgan's for boolean operators, commutativity for sums, distributivity for sum/product, transformation of integral division in an appropriate multiplication, ...) can be employed only when the "real operators" are used.
Notice instead that some parts of the standard library may associate some specific semantic meaning to overloaded operators - for example, std::sort by default expects an operator< that complies to a strict weak ordering between the elements - but this is of course listed in the prerequisites of each algorithm/container.
(incidentally, overloading && and || should probably be avoided anyway since they lose their short-circuiting properties when overloaded, so their behavior becomes surprising and thus potentially dangerous)
You are asking whether the compiler can arbitrarily rewrite your program to do something you did not write it to do.
The answer is: of course not!
Where De Morgan's laws apply, they may be applied.
Where they don't, they may not.
It's really that simple.
Not directly.
If p and q are expressions so that p does not have overloaded operators, short circuit evaluation is in effect: expression q is going to be evaluated only if p is false.
If p is of non-primitive type, there is no short circuit evaluation and overloaded function could be anything - even not related to the conventional usage.
Compiler will do its optimizations in its own way. Perhaps it might result de Morgan identities, but not on the level of if condition replacement.
DeMorgan's laws apply to the semantics of those operators. Overloading applies to the syntax of those operators. There is no guarantee that an overloaded operator implements the semantics that are needed for DeMorgan's laws to apply.
But in C++ it is possible to overload operators, and the overloaded operator may not always respect this property.
Overloaded operator is no longer an operator, it is a function call.
class Boolean
{
bool value;
..
Boolean operator||(const Boolean& b)
{
Boolean c;
c.value = this->value || b.value;
return c;
}
Boolean logical_or(const Boolean& b)
{
Boolean c;
c.value = this->value || b.value;
return c;
}
}
So this line of code
Boolean a (true);
Boolean b (false);
Boolean c = a || b;
is equivalent to this
Boolean c = a.logical_or(b);

Is there any good reason C++ doesn't permit doubling the -> operator?

In C++, you can double up the indirection operator:
vector<unique_ptr<string>> arr{make_unique<string>("Test")};
cout << **arr.begin() << endl;
But you can't double up the dereference operator:
cout << arr.begin()->->c_str() << endl;
Instead, you have to settle with this (IMO) less-legible alternative:
cout << (*arr.begin())->c_str() << endl;
operator-> is a unary operator that returns a pointer type, so it seems natural to be able to chain them. Is there any good reason for this limitation? Is there some parsing difficulty I'm not seeing?
Edit
In 5.2.5/3, The C++ standard specifies:
If E1 has the type “pointer to class X,” then the expression E1->E2 is
converted to the equivalent form (*(E1)).E2
I just wish it was specified as:
If E1 has the type “pointer to class X,” then the expression E1-> is
converted to the equivalent form (*(E1)).
It actually seems contrary for this definition to include E1 and E2, since an overloaded operator-> isn't a binary operator.
Here is a not too technical explanation.
-> is shorthand for the * and the . in (*someptr).memberfunc(). Therefore this can be expressed as someptr->memberfunc().
Two -> would be, in your example, the same as (*(*arr.begin()).).c_str(). Notice the extra dot. This doesn't make sense and it doesn't compile, since . is a binary operator, and * is a unary operator. Therefore, you would have an "extra" dot. You really want two *'s and only one .. Use one -> and one * as you have done.
-> means "dereference and get a member." You want to dereference twice, and get a member once, so double -> is not what you want.
Note that:
(*a).b
a->b
are the same thing
so
a->->b
(*a)->b
(*(*a)).b
So would be okay as an operator, but that isn't in the spirit of -> the spirit is to access things that are pointed to in structures. I'd rather type a->b than (*a).b
So while no technical reason (*a)->b tells you "a is a pointer to a pointer of a structure with b" and a->b->c is totally different to a->->b even though they look similar.
If I understand this correctly, You can get the behaviour that you are looking for with a better design.
The dereference operator actually doesn't really works just as an operator that retrieves a values for you from a pointer, if offers a slightly more complex behaviour.
The business logic of the -> operator is clearly illustrated here, it is also being expanded here, here and you can find a birds eye view about pointer related operators here .
As you can easily guess, If you have T->t you can use the drill down behaviour at your advantage, assuming that you have properly designed and defined T and its own -> operator.
This is a solution that can easily bring some polymorphic behaviour to your application.

Trying to understand more about operator associativity in OCaml

I got quite confusioned about associativity in OCaml.
Let's have some examples first.
1. Is + left associative or right?
I think it is left associative. which means if we have a + b + c + d, then it is ((a+b)+c)+d.
But what if we do f1 1 + f2 2? Will it throw an error? because it should be ((f1 1)+f2) 2, right?
2. :: is right associative, but what if used with ,?
If we do 4,3::[], then we have [4,3]. it will create a tuple (4,3), then :: into [].
then why doesn't 4,3::5,6::[] work?
3. functions
Say we have let f x y = y x 5, so y is a function taking two parameters.
If we do f 1 + 2, because + is actually a function taking two parameters, why won't f 1 + 2 work? Why doesn't + become a parameter of f?
4. right associativity
How to create a infix function with right associativity?
Basically, I guess I haven't understood the whole associative / precedence thing in OCaml.
I know there are tables like this http://caml.inria.fr/pub/docs/manual-caml-light/node4.9.html out there. But can someone explain more to me?
Operator associativity determines how to parse an expression when there are multiple operators with the same precedence. For example, a + b + c has two operators with the same precedence (+ and +), so the associativity determines how to parse that expression: the operator is left-associative, so the expression is equivalent to (a + b) + c.
In the expression f1 1 + f2 2, juxtaposition (f1 1 and f2 2) has higher precedence than +, so the expression is equivalent to (f1 1) + (f2 2). There aren't two or more operators at the same precedence level, so associativity doesn't matter.
Your statement about 4,3::[] is wrong: :: has higher precedence than ,, so it is parsed as 4, (3::[]), not (4,3)::[]. The result is a pair whose second element is a list. Read the type error for 4,3::5,6::[]: it is equivalent to (4, (3::5), (6::[])), thus the compiler complains that 5 has type int but the context (due to the :: operator) requires a list.
When you write f 1 + 2, it is parsed as (f 1) + 2. The function f is applied to an integer argument; since f expects two arguments, the result is a function (waiting for the second argument), but the + operator wants an integer, so the expression is ill-typed. + isn't a parameter of f because + by itself is not an expression, and the argument of a function is an expression.
I don't know what you mean by “infix function with right associative”. The associativity and precedence of operators in Ocaml is determined by the first character of the operator as indicated in the table you link to.
These are all standard concepts in parsing, applicable to almost every programming language out there. I recommend reading any textbook with a chapter on programming language syntax or parsing, or start with the Wikipedia articles on associativity and precedence.

Overload power with correctly in c++?

In c++ I implemented an integer class and I overloaded operator ^ to be the power function.
integer integer::operator^ (const integer& rhs){
return integer(pow(this->.i, rhs.i));
}
This is working correctly for two operands.
integer i1, i2, i3 ;
i4 = i1 ^ i2 ^ i3;
The value of i4 is wrong mathematically because associativity required right-to-left. How can I solve this problem? How do I change associativity?
I got reasonable answers and I learn:
-We can't change associativity or priority of an operator.
-Good is Not to overload operators to do something conceptually different to
the built-in versions
-Even compiler can't support; it hard to implement!
You cannot change the associativity or priority of an operator in C++ by overloading it. These rules are hardwired into the language syntax.
The C++ standard says (§13.5.6, emphasis mine):
An operator function shall either be a non-static member function or be a non-member function and have
at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an
enumeration. It is not possible to change the precedence, grouping, or number of operands of operators.
The meaning of the operators =, (unary) &, and , (comma), predefined for each type, can be changed [...]
Not only is the ^ operator left-associative, but it also has a very low precedence. The correct precedence for a power operator should be higher than the multiplication (so priority 4 or better on this table), but it has priority 10--this means that even additions and subtractions are evaluated before it. 1 + 2 ^ 3 * 4 will be parsed as (1 + 2) ^ (3 * 4), while a mathematically correct power operator should parse as 1 + (2 ^ 3) * 4.
If the associativity or priority of an operator could be modified, a huge, huge syntactical mess would ensue. My humble opinion is that you should not try to overload the ^ operator to use it as a power operator. I would rather make a power method on the class.