2
$\begingroup$

Considering how often we do:

variable = variable + another;
variable = variable - another;
variable = variable * another;
variable = variable / another;
variable = variable & another;
variable = variable | another;
variable = variable ^ another;

we then made the following language shortcuts:

variable += another;
variable -= another;
variable *= another;
variable /= another;
variable &= another;
variable |= another;
variable ^= another;

so, then, considering how often we do this:

variable = variable.different();
// or variable = variable->different();
// or variable = variable::different();

(for instance, stringVar = stringVar.toUpperCase()), why isn't there one of these?

variable .= different();
// or variable ->= different();
// or variable ::= different();

is it a parsing issue? Would it be too hard? Or is there some obvious thing I don't see here?

I'm not asking for opinions, here. I want to know if there's any documented, historic, technical, or other verifiable reasons for why there is no such operator.

$\endgroup$
7
  • 3
    $\begingroup$ This looks pretty subjective. What kind of answer do you expect? It might just have been an arbitrary decision made by language designers, for all I know. We look for questions that will attract answers that can be supported with facts, references, and evidence, and that can be judged objectively based upon evaluation criteria specified in the question. Maybe if you narrow it down to just asking about parsing... As far as your question: Have you done any quantitative research? How often does variable = variable.different(); appear in code? $\endgroup$
    – D.W.
    Aug 2, 2014 at 1:19
  • 2
    $\begingroup$ @D.W. And is it so often that replacing it with variable.set_different() would make more sense? (If different() is only used for updating the calling object, then using the assignment operator may not be the best syntax anyway.) $\endgroup$
    – user4577
    Aug 2, 2014 at 2:18
  • 1
    $\begingroup$ @Supuhstar, I was asking if you've measured how often x = x.m() occurs in code, compared to x = x + y / x += y. It's possible that language designers thought x = x.m() would be rare. In C, I would expect it is rare. But your example helps -- it suggests that this probably applies only to immutable types; for mutable types, we'd be more likely to use a different idiom, as Paul Clayton mentions. For instance, maybe the designers of C figured it'd be rare, and the other languages just copied from C. But this is speculation; I don't know how we'd ever get evidence. $\endgroup$
    – D.W.
    Aug 2, 2014 at 5:34
  • 2
    $\begingroup$ What language are you talking about? $\endgroup$ Aug 2, 2014 at 8:47
  • 1
    $\begingroup$ I think that in some languages (e.g. Scala) creating such syntax (i.e. methods called like operators that look like syntax) is possible. $\endgroup$
    – Raphael
    Aug 2, 2014 at 10:45

5 Answers 5

6
$\begingroup$

IMO, the biggest reason is that identifiers are not first class values in programming languages and "." is not a real operator like + or - are. For example, you can't convert

var foo = variable.bar()

into

var name = bar
var foo = variable.name()

The same way you can convert

var foo = 1 + 10

into

var x = 10
var foo = 1 + x

In more technical terms, in most languages x + y is an expression, while x, x.y and x[i] are identifiers.

Summing up, when using your hypothetical .=, the right hand side needs to be interpreted as a field name, not an expression. This leads to unintuitive results - the following two lines look very similar but do wildly different things.

x += bar() // calls the bar() global function and add its value to x
y .= bar() // calls y's bar() method, and sets `y` to its result.

Additionally, as Guy Coder pointed out, when using +, -, etc its guaranteed that the type of the resulting expression is the same as the arguments so += always makes sense. On the other hand, we can have y.bar() return a type different from y, in which case .= bar() would make no sense.

$\endgroup$
3
  • $\begingroup$ Very nice pointing out the difference between expressions and identifiers! I'd forgotten about that entirely! $\endgroup$
    – Ky -
    Aug 4, 2014 at 2:54
  • 1
    $\begingroup$ Identifiers aren't 1st class citizens in most programming languages. There are ones that do things right. $\endgroup$
    – mike3996
    Aug 5, 2014 at 7:59
  • $\begingroup$ "when using +, -, etc its guaranteed that the type of the resulting expression is the same as the arguments" Not really, at least not in all languages. For example in C#, the result of adding two bytes is an int. Though this results in weird situations, where for example b1 = b1 + b2; doesn't compile, but b1 += b2; does. $\endgroup$
    – svick
    Sep 23, 2014 at 2:04
3
$\begingroup$

In the situtation: variable += another; you have 2 variables, 1 operator and 1 assignment.

In the situtation: variable ->= different() you have 1 variable, 1 method access operator ( i.e ->), 1 method name that needs to be called and 1 assignment.

When a language's syntactic sugar feature is designed, one important concept to consider is composition, i.e how elegantly you can compose these syntactic sugar based expressions.

In the first example you can create a chain of these operations:

variable *= another_var -= variable += another;

Whereas there is no simple way to do this kind of composition in the second case. Lets say we have the below code:

variable = variable.method1();
another_var = variable.method2(params);

If you try to apply the approach that you suggested, you will get into weird situtation:

another_var .= <what should be here> variable .= method1()

In the method based case there is pattern called "fluent API design". You can use that to express the above code elegantly.

another_var = variable.method1().method2(params);

Hope this helps.

$\endgroup$
2
  • 1
    $\begingroup$ your example with chaining is good, but wouldn't that also break down if the first or any middle variable was actually a constant? $\endgroup$
    – Ky -
    Aug 3, 2014 at 1:20
  • $\begingroup$ Any attempt at assignment to a constant would fail (after initialization). If you want to use a constant, don't try assigning to it, that's not what constants are for. $\endgroup$ Aug 3, 2014 at 13:15
3
$\begingroup$

The reason it is not done is because the type of the result may not be the same as the type of the receiving term.

In the examples you gave the result and receiving terms are the same type or it is common to coerce the type of the result into the receiving term type which is common with mathematical operators.

Standard way
Int = Int + Int

Syntactic sugar
Int += Int

Receiving Term  Other Term  Result  
Int             Int         Int  
Float           Int         Float  
Float           Float       Float  

If it is taken that -> means pointer then you would have

Standard way
Name = Person -> Name

Your way
Person ->= Name

Receiving Term  Other Term  Result  
Object          String      String  

So setting an object to a string would either cause the type of the object to become a string which may not be desired or the compiler might throw an exception.

Standard way
Color = Bird -> Color

Your way
Bird ->= Color

Receiving Term  Other Term  Result
Bird            Color       Color

Obviously a bird should not be a color but can have a color.

$\endgroup$
1
  • $\begingroup$ I actually meant the "Standard way" to be Color = Color->Bird, and "my way" to be Color ->= Bird $\endgroup$
    – Ky -
    Aug 4, 2014 at 2:50
2
$\begingroup$

The simple thing is we rarely found this situation for using like this

 variable = variable.different();
// or variable = variable->different();
// or variable = variable::different();

since we call a function with objects and assign the return value to the variable and normally we never return an object back to the same in old days.

there fore the compiler designer will never think about giving special meaning to the .= or ->=

but if you take the examples of arithmetic operators we will found this may be in every program like tormenting adding etc .

but when the concept of OOP is increased rapidly one need to think about giving such a special meaning..

$\endgroup$
1
  • $\begingroup$ So your perspective is that, in these use cases, you find it more common that variable.different() would be a mutating method, so such reassignment is unnecessary? Interesting - I was thinking of things like myString.substring(2...5), which returns a value without mutating anything $\endgroup$
    – Ky -
    Dec 18, 2020 at 19:28
1
$\begingroup$

I would like to build on hugomg with this example from JavaScript:

var foo = variable.bar()

can be rewritten as

var name = "bar";
var foo = variable[name]();

When it comes down to it, . is just as much an operator as +. It's a binary operator who's left side must be an object, and who's right side should be a property name in that object. In ES at least, for property names that don't fit the identifier requirements, there's a different notation that does the same thing.

Further, while x is an identifier and y is also an identifier, x.y is an expression, not significantly different from 1+2 except in how it is carried out. The simple fact that the . operation can be interfered with (via Proxy) is proof that x.y is not simply an identifier.

The real reason why .= is not an operator is simply that it makes code harder to read and understand, even for the engine. Consider this:

function add(a=0, b=0) {
  return a + b;
}

some.preexisting.obj.with.an.add.function .= add(3);

This would be valid code, but confusing as heck. Without the dot in .=, the add function in this example would be called. However, with it, the add function belonging to that ridiculous object would be called. This goes against some basic understandings about the nature of ES function calls. In short, it's just a bad idea.

$\endgroup$
3
  • $\begingroup$ Welcome to COMPUTER SCIENCE @SE. Prefer hyperlinking to an answer like hugomg's or comment you are referring to over stating an ordinal number, which may change. $\endgroup$
    – greybeard
    Dec 18, 2020 at 7:25
  • $\begingroup$ Note that hugomg's answer continues to read can't convert [plain access] into [two steps] the same way you can convert [plain access] into [two steps], if misleadingly capitalising The same…. (I think you are right pointing out the availability of mechanisms at the source code level with "object oriented languages conceptually interpreted". I think the argument from the question does apply to languages like C, especially those sporting assignment operators beyond "basic".) $\endgroup$
    – greybeard
    Dec 18, 2020 at 7:46
  • $\begingroup$ Fascinating perspective on hugomg's answer - thank you for chipping in your 2¢! I think the most valuable thing you pointed out is that it would be difficult to disambiguate using a global function versus a member function in this context 😁 $\endgroup$
    – Ky -
    Dec 18, 2020 at 19:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.