Jump to page: 1 2
Thread overview
infix functions as a substitute for operator overloading?
Feb 13, 2002
Richard Krehbiel
Feb 13, 2002
Russ Lewis
Feb 13, 2002
Richard Krehbiel
Feb 13, 2002
Russ Lewis
Feb 17, 2002
OddesE
Feb 17, 2002
Pavel Minayev
Feb 18, 2002
Russ Lewis
Feb 18, 2002
OddesE
Feb 13, 2002
Pavel Minayev
Feb 13, 2002
Russell Borogove
Feb 17, 2002
OddesE
Feb 13, 2002
Roland
February 13, 2002
My thinking: Why does operator overloading exist?

I think the primary reason is to allow an infix notation for user-defined functions.

Common compiler construction technology (YACC, PCCTS) requires the syntax be fixed; the set of infix tokens is fixed, their precedence is fixed, their associativity is fixed.

But maybe we've progressed beyond that.  What if it were possible for the user to simply declare a function as "infix?"

infix int plus(int a, int b) { return a + b; }

Now you can code:

  int x, y, z;
  z = x plus y;

Pretty readable.  Clearly "plus" is a user- (or library-) defined operation, and I *like* making that clear to the reader.

That leaves precedence and associativity.  Right now I'd guess that it would be okay if all infix operators would have lower precedence than all built-in operators.  We can also simplify by giving all infix functions equal precedence, and make the user group them as needed by parentheses, but it might be nice to be able to specify their associativity (does "a plus b plus c" do "b plus c" first, or "a plus b" first?).

Now, ISTR that the current alpha D compiler is a hand-coded recursive-descent parser, and I'm pretty sure that a smart man like Walter could in fact code up syntactic analyser that is tolerant of additions to the infix operator table (eh, Walter?).  But it means you can't build D compilers with YACC (um, maybe; if you leave out user control of precedence and associativity, I think it could still be done).  Oh, and it means feeding back info from semantic analysis into syntax, and I recall reading that Walter has decided this is bad (the reasoning for his syntactic changes to type-casting operations).

Well, it was a thought.

--
Richard Krehbiel, Arlington, VA, USA
rich@kastle.com (work) or krehbiel3@home.com (personal)



February 13, 2002
Richard Krehbiel wrote:

> But it means you can't build D
> compilers with YACC (um, maybe; if you leave out user control of precedence
> and associativity, I think it could still be done).  Oh, and it means
> feeding back info from semantic analysis into syntax, and I recall reading
> that Walter has decided this is bad (the reasoning for his syntactic changes
> to type-casting operations).

Can you describe why this is impossible with YACC?  As I understand it, what
YACC really sees is
    <token> = <token> <token> <token>  ;

Which it would parse into blocks something like
    blockA:        x plus y
    blockB:        z = <blockA>
    blockC:        <blockB>   ;
It's the responsibility of the compiler code supplied with the blockA rule to
determine what those 3 alphanumeric tokens mean.  It's not particularly
different from
    foo bar;
which the compiler must deduce (from semantics) is a variable declaration.

Maybe I'm missing something again...

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


February 13, 2002
"Richard Krehbiel" <rich@kastle.com> wrote in message news:a4dqip$28i7$1@digitaldaemon.com...

>   int x, y, z;
>   z = x plus y;
>
> Pretty readable.  Clearly "plus" is a user- (or library-) defined
operation,
> and I *like* making that clear to the reader.

Hey, I still want to be able to overload + as is! =)


February 13, 2002
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:3C6A7779.27137005@deming-os.org...
> Richard Krehbiel wrote:
>
> > But it means you can't build D
> > compilers with YACC (um, maybe; if you leave out user control of
precedence
> > and associativity, I think it could still be done).  Oh, and it means feeding back info from semantic analysis into syntax, and I recall
reading
> > that Walter has decided this is bad (the reasoning for his syntactic
changes
> > to type-casting operations).
>
> Can you describe why this is impossible with YACC?  As I understand it,
what
> YACC really sees is
>     <token> = <token> <token> <token>  ;
>
> Which it would parse into blocks something like
>     blockA:        x plus y
>     blockB:        z = <blockA>
>     blockC:        <blockB>   ;
> It's the responsibility of the compiler code supplied with the blockA rule
to
> determine what those 3 alphanumeric tokens mean.  It's not particularly
> different from
>     foo bar;
> which the compiler must deduce (from semantics) is a variable declaration.
>
> Maybe I'm missing something again...

Here's a YACC (like) expression of some of the C grammar, taken from the back of K&R's "The C Programming Language:"

shift_expr:
     add_expr
   | shift_expr '<<' add_expr
   | shift_expr '>>' add_expr;

add_expr:
     mul_expr
   | add_expr '+' mul_expr
   | add_expr '-' mul_expr;

mul_expr:
     cast_expr
   | mul_expr '*' cast_expr
   | mul_expr '/' cast_expr
   | mul_expr '%' cast_expr;

Precedence is defined in the grammar, that is, the grammar (which can't be
changed at run time) defines that a mul_expr has higher precedence than
add_expr and shift_expr (so "a + b * c" evaluates as "a + (b * c)").

Associativity is also defined in the grammar.  Associativity says that if you have "a + b - c" it's evaluated as "(a + b) - c" (um, probably; C can reorder these, and you can tell by side-effects, if it can prove that otherwise the result is indistinguishable - and if overflow is possible, then it can be).

Associativity matters a great deal if the side effects matter, like with the C++ "<<" iostream operator.  When you code 'cout << "result is " << i << endl;', the output must go left-to-right.

What I was saying is, if we rule that user-defined infix operators always and forever have a particular precedence and associativity, then we *can* build such a compiler with YACC.

Assuming that the above was the top of the "expression" definition (it's
not), we'd add:

user_infix_expr:
      shift_expr
    | user_infix_expr INFIX_TOKEN shift_expr;

And then, we'd tell the lexer that user-defined infix function names be returned as INFIX_TOKEN rather than as IDENTIFIER_TOKEN.

Now, with a recursive-descent parser written in plain C, precedence and associativity rules could also be changed at run time.  But you still need to know it's an "infix operator", not an "identiier", which means feedback.

(...and I'm sure that *real* compiler designers will correct any of this
that's wrong...)

--
Richard Krehbiel, Arlington, VA, USA
rich@kastle.com (work) or krehbiel3@home.com (personal)



February 13, 2002
Richard Krehbiel wrote:

> What I was saying is, if we rule that user-defined infix operators always and forever have a particular precedence and associativity, then we *can* build such a compiler with YACC.

Gotcha!  Now I understand.

Frankly, it seems like left-to-right precedence/associativity makes sense for the majority of applications.  Anybody got (good) counterexamples?

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


February 13, 2002
Richard Krehbiel a écrit :

> My thinking: Why does operator overloading exist?
>
> I think the primary reason is to allow an infix notation for user-defined functions.
>
> Common compiler construction technology (YACC, PCCTS) requires the syntax be fixed; the set of infix tokens is fixed, their precedence is fixed, their associativity is fixed.
>
> But maybe we've progressed beyond that.  What if it were possible for the user to simply declare a function as "infix?"
>
> infix int plus(int a, int b) { return a + b; }
>
> Now you can code:
>
>   int x, y, z;
>   z = x plus y;
>
> Pretty readable.  Clearly "plus" is a user- (or library-) defined operation, and I *like* making that clear to the reader.
>

I already suggested something like this (see "Operator overloading, ann other
idea").
I was not convinced by counter arguments.
So i still support infix notation

Roland



February 13, 2002
Pavel Minayev wrote:
> "Richard Krehbiel" <rich@kastle.com> wrote in message
> news:a4dqip$28i7$1@digitaldaemon.com...
> 
> 
>>  int x, y, z;
>>  z = x plus y;
>>
>>Pretty readable.  Clearly "plus" is a user- (or library-) defined
>>
> operation,
> 
>>and I *like* making that clear to the reader.
>>
> 
> Hey, I still want to be able to overload + as is! =)

For a second, I thought Richard's suggestion was a valuable
compromise.

But when you think about it, it just _looks_ like... I
don't know. Baby talk. Training wheels. Writing with crayon.
(No offense intended.)

Once you start trying to write a big hairy expression
with "plus", you're going to want to rename it "pl" then
"p" (or "add", then "a") to save space on the line. At
that point you've hurt readability more than if you had
overloaded the plus sign. Likewise, you still can't
reasonably enforce against writing a "plus" function that,
say, appends to a file on the disk. So who are we kidding?

Unless you're going to vastly alter the way D is specified
now, Walter, there are going to be a million ways to write
misleading and crappy code. Giving us overloaded operators
in the style of C++[1], or not, isn't materially going to
change that. Many people want the overloaded operators. I
don't know what other arguments I can make.

Okay, okay, here's one more.

Bignums. If I want to create a class that manages arbitrary-
precision, arbitrary-magnitude numbers, I want to manipulate
them using the conventional mathematical operators. :+: and
other weirdness isn't going to help readability.

-Russell B

[1] And by that I mean without substantially restricting the
operator list from C++ -- sure, get rid of . and -> and , but
leave the bitwise, logical, and comparison operators in.



February 17, 2002
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:3C6A891A.A5881559@deming-os.org...
> Richard Krehbiel wrote:
>
> > What I was saying is, if we rule that user-defined infix operators
always
> > and forever have a particular precedence and associativity, then we
*can*
> > build such a compiler with YACC.
>
> Gotcha!  Now I understand.
>
> Frankly, it seems like left-to-right precedence/associativity makes sense
for
> the majority of applications.  Anybody got (good) counterexamples?
>

CInt256 a = 1, b = 2, c = 5;

a = a + b * c;

// Should yield 11, not 15....


--
Stijn
OddesE_XYZ@hotmail.com
http://OddesE.cjb.net
__________________________________________
Remove _XYZ from my address when replying by mail





February 17, 2002
"Pavel Minayev" <evilone@omen.ru> wrote in message news:a4duo0$2ao6$1@digitaldaemon.com...
> "Richard Krehbiel" <rich@kastle.com> wrote in message news:a4dqip$28i7$1@digitaldaemon.com...
>
> >   int x, y, z;
> >   z = x plus y;
> >
> > Pretty readable.  Clearly "plus" is a user- (or library-) defined
> operation,
> > and I *like* making that clear to the reader.
>
> Hey, I still want to be able to overload + as is! =)
>
>

Me too!


--
Stijn
OddesE_XYZ@hotmail.com
http://OddesE.cjb.net
__________________________________________
Remove _XYZ from my address when replying by mail



February 17, 2002
"OddesE" <OddesE_XYZ@hotmail.com> wrote in message news:a4o5g5$rgm$1@digitaldaemon.com...

> CInt256 a = 1, b = 2, c = 5;
>
> a = a + b * c;
>
> // Should yield 11, not 15....

He said "user-defined", not "built-in".
For user-defined, I guess we can live with fixed precedence,
using braces where necessary...


« First   ‹ Prev
1 2