Topic: proposal: operator void


Author: mikup@land.ru (Mikhail Kupriyanuk)
Date: Wed, 14 Nov 2001 23:20:59 GMT
Raw View
"Heinz Ozwirk" <wansor42.NOSPAM@gmx.de> wrote in message news:<9sjd46$err$03$1@news.t-online.com>...
> "Mikhail Kupriyanuk" <mikup@land.ru> schrieb im Newsbeitrag
> news:69ed2810.0111090248.5004a313@posting.google.com...
> > "Andrei Iltchenko" <iltchenko@yahoo.com> wrote in message
>  news:<9sdsdo$lhq@news.nl.compuware.com>...
> > Consider statements
> >
> >     a = b*c;
> >     &#1089; = (a-b) * (c-d);
> >     b && (c = d) || (c = a);
>
> An implicit void (or better evaluate) operator as you suggested it doesn't
> help. What about statements like
>
>     x = (a=b*c, (a-b)*(c-d));
>
> ? How would you implement all the side effects that might happen? And what
> about something like
>
>     a+b;
>
> ? If you have lazy evaluation, there is now reason to evaluate such an
> expression, but your 'proposal' would result in a very expansive no-op.

As it seems to me, complexity of expression doesn't matter at all. An
implementation is leaved to programmer, and I do not see why
programmer won't be able to have it done.
Second is simple :). a+b is of type 'proxy' with operator void, then
there's a call to operator void. In the case if a+b is of type without
operator void defined then 'automatic' operator void will be zero cost
no-op, just as 'automatic' default constructor.

> And you don't need an operator like that. There are lots of lazy evaluation
> implementations around, that do very well without it. All you have to do, is
> add a constructor to your objects, that accept a proxy and evaluate it. If
> you'd do a really good job, you'd also supply an assignment operator, that
> evaluates the expression proxy and assigns it.

Your solution leads to giving special look to lazy expressions, some
like

   SPEC(x = (a=b*c, (a-b)*(c-d)));

or

   SPEC = (x = (a=b*c, (a-b)*(c-d)));

Right? If so, it's not bad deal though. But operator void is better!
:)

  1) It would allow natural syntax here.

  2) It would remove unnecessarily exceptional treatment of type void.
Indeed, what a discrimination: void casts are prohibited while all
others are not.

  3) As a bonus, it might solve the 'void return' problem:

void f()
{
   return MyObject; //MyObject casts to void, no error here
}

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Jens Kilian <Jens_Kilian@agilent.com>
Date: Thu, 15 Nov 2001 16:58:00 GMT
Raw View
mikup@land.ru (Mikhail Kupriyanuk) writes:
> Right? If so, it's not bad deal though. But operator void is better!
> :)
>
>   1) It would allow natural syntax here.
>
>   2) It would remove unnecessarily exceptional treatment of type void.
> Indeed, what a discrimination: void casts are prohibited while all
> others are not.
>
>   3) As a bonus, it might solve the 'void return' problem:
>
> void f()
> {
>    return MyObject; //MyObject casts to void, no error here
> }

It would also allow some interesting techniques to catch programming errors.
(See the thread "Exploding return codes" on comp.lang.c++.moderated, from
 a year ago; you can find it via Google Groups.)
--
mailto:jjk@acm.org                 phone:+49-7031-464-7698 (TELNET 778-7698)
  http://www.bawue.de/~jjk/          fax:+49-7031-464-7351
PGP:       06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Christopher Eltschka <celtschk@web.de>
Date: Thu, 15 Nov 2001 17:46:32 GMT
Raw View
mikup@land.ru (Mikhail Kupriyanuk) writes:

> Good day, all.
>
> First of all excuse me for possibly reinventing the wheel.
> Let me start with proposal itself, then I'll try to do some
> explanation should any required.
>
> This proposal introduces some new compiler behavior while leaving all
> the existing rules correct and not breaking any existing code ;)
>
>      1.  Require that any expression should be of type void if it is a
> statement-expression (ie expression followed by a semicolon thus
> representing a statement)
>
>        "statement-expression" :-  "expression" ";"
>
>      2.  If the result of such expression is not of type void, then
> operator void is called to cast the type to type void.

[...]

> I'd glad to see comments on this. Any opinions are welcome.

Your change could break the following code:

extern volatile int hardware_control_word;

int reset_hardware()
{
  hardware_control_word = 0;
  return hardware_control_word;
}

In C++ operator= returns an lvalue. Your change would cause an lvalue
to rvalue conversion of the result, which due to volatile may result
in an extra access to the variable hardware_control_word, which may
cause some action in the hardware (say, reading the variable directly
after reset gives some status word; the next read gives some other
data. Now code calling this function might not any more get the
hardware control word it used to get, but instead the other data,
because the lvalue to rvalue conversion at the assignment statement
caused a read of the hardware register, and the return statement
caused a second one).

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: mikup@land.ru (Mikhail Kupriyanuk)
Date: Wed, 7 Nov 2001 22:58:26 GMT
Raw View
Good day, all.

First of all excuse me for possibly reinventing the wheel.
Let me start with proposal itself, then I'll try to do some
explanation should any required.

This proposal introduces some new compiler behavior while leaving all
the existing rules correct and not breaking any existing code ;)

     1.  Require that any expression should be of type void if it is a
statement-expression (ie expression followed by a semicolon thus
representing a statement)

       "statement-expression" :-  "expression" ";"

     2.  If the result of such expression is not of type void, then
operator void is called to cast the type to type void.

     3.  If the type has no operator void defined, an
automatically-generated operator void is used. This compiler's
operator void is required to have a 'do nothing' semantics.

     4.  It might be useful to require operator void to be member of a
class. This will prevent breaking existing code by defining weird
operator void for plain type, such as int.

Now one may ask why to bother of this.
Well, it would allow to implement what I call 'expression completion'
idiom. Expression may contain some kind of 'lazy evaluation'
semantics. I consider proposed operator void as the best place to
carry out all the delayed job. Without being able to 'complete'
evaluation of expression, one ends up with giving exactly that meaning
to operator=. This is evil in two ways:
  1) user is forced to assign the result
  2) expression may contain assignment in some part of it. In this
case premature evaluation would surely lead to inefficiency.
Generally speaking, the problem raises from giving special meaning to
regular operator, which is not unique in any other way.

I'd glad to see comments on this. Any opinions are welcome.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Dietmar Kuehl <dietmar_kuehl@yahoo.com>
Date: Thu, 8 Nov 2001 16:13:12 GMT
Raw View
Hi,
Mikhail Kupriyanuk wrote:

> Well, it would allow to implement what I call 'expression completion'
> idiom. Expression may contain some kind of 'lazy evaluation'
> semantics. I consider proposed operator void as the best place to
> carry out all the delayed job. Without being able to 'complete'
> evaluation of expression, one ends up with giving exactly that meaning
> to operator=.


I'd rather say that this something implemented in the destructor an
appropriate type... Also, you might want to have a look at expression
templates.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Edward Diener <eldiener@earthlink.net>
Date: Thu, 8 Nov 2001 19:08:28 CST
Raw View
Mikhail Kupriyanuk wrote:

> Good day, all.
>
> First of all excuse me for possibly reinventing the wheel.
> Let me start with proposal itself, then I'll try to do some
> explanation should any required.
>
> This proposal introduces some new compiler behavior while leaving all
> the existing rules correct and not breaking any existing code ;)
>
>      1.  Require that any expression should be of type void if it is a
> statement-expression (ie expression followed by a semicolon thus
> representing a statement)
>
>        "statement-expression" :-  "expression" ";"
>
>      2.  If the result of such expression is not of type void, then
> operator void is called to cast the type to type void.
>
>      3.  If the type has no operator void defined, an
> automatically-generated operator void is used. This compiler's
> operator void is required to have a 'do nothing' semantics.
>
>      4.  It might be useful to require operator void to be member of a
> class. This will prevent breaking existing code by defining weird
> operator void for plain type, such as int.
>
> Now one may ask why to bother of this.
> Well, it would allow to implement what I call 'expression completion'
> idiom.


What purpose does 'expression completion' have ? How is it supposed to
be used and what area of C++ is it supposed to fill ? I don't see any
purpose for this complication of creating automatic type void.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Thu, 8 Nov 2001 19:08:31 CST
Raw View
"Mikhail Kupriyanuk" <mikup@land.ru> wrote in message
news:69ed2810.0111071454.37a772d1@posting.google.com...

> This proposal introduces some new compiler behavior while leaving all
> the existing rules correct and not breaking any existing code ;)

What you propose has the potential of not only breaking user code, but also
the whole syntactic grammar of the language.


>      1.  Require that any expression should be of type void if it is a
> statement-expression (ie expression followed by a semicolon thus
> representing a statement)
>
>        "statement-expression" :-  "expression" ";"

Given the above definition of what you call an 'statement-expression' and
the current definition of the 'expression-statement' production, which is
    expression-statement:
        expression opt ;
What would the following sequence of tokens represent?
i;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Whould that be an expression or a statement or both?

The language defines the 'jump-statement' production as:
    jump-statement:
       continue;
       break;
       goto identifier;
       return expression opt ;

Now consider the jump-statement from the body of the function called 'foo':
int  foo()
{   return  5;   }
With your definition of your 'statement-expression' the above definition
would always be ill-formed, for a semicolon to complete the return statement
would always be missing.

By the way did you think of what precedence the new 'statement-expression'
should have, in case you want declarations like this 'int   i = 5;' to make
sense?


>      2.  If the result of such expression is not of type void, then
> operator void is called to cast the type to type void.
>
>      3.  If the type has no operator void defined, an
> automatically-generated operator void is used. This compiler's
> operator void is required to have a 'do nothing' semantics.
>
>      4.  It might be useful to require operator void to be member of a
> class. This will prevent breaking existing code by defining weird
> operator void for plain type, such as int.
>
> Now one may ask why to bother of this.
> Well, it would allow to implement what I call 'expression completion'
> idiom. Expression may contain some kind of 'lazy evaluation'
> semantics.

Can you give some examples of your 'expression completion' idiom and the
'lazy evaluation' semantics?


> I consider proposed operator void as the best place to
> carry out all the delayed job. Without being able to 'complete'
> evaluation of expression, one ends up with giving exactly that meaning
> to operator=.
> This is evil in two ways:
>   1) user is forced to assign the result
>   2) expression may contain assignment in some part of it. In this
> case premature evaluation would surely lead to inefficiency.
> Generally speaking, the problem raises from giving special meaning to
> regular operator, which is not unique in any other way.

Give examples of well-formed C++ code that suffers from the problem you
found!


Regards,

Andrei Iltchenko.





---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: mikup@land.ru (Mikhail Kupriyanuk)
Date: Fri, 9 Nov 2001 10:16:31 CST
Raw View
Edward Diener <eldiener@earthlink.net> wrote in message news:<3BE9FB08.9030903@earthlink.net>...

> Mikhail Kupriyanuk wrote:
>
> > Good day, all.
> >
> > First of all excuse me for possibly reinventing the wheel.
> > Let me start with proposal itself, then I'll try to do some
> > explanation should any required.
> >
> > This proposal introduces some new compiler behavior while leaving all
> > the existing rules correct and not breaking any existing code ;)
> >
> >      1.  Require that any expression should be of type void if it is a
> > statement-expression (ie expression followed by a semicolon thus
> > representing a statement)
> >
> >        "statement-expression" :-  "expression" ";"
> >
> >      2.  If the result of such expression is not of type void, then
> > operator void is called to cast the type to type void.
> >
> >      3.  If the type has no operator void defined, an
> > automatically-generated operator void is used. This compiler's
> > operator void is required to have a 'do nothing' semantics.
> >
> >      4.  It might be useful to require operator void to be member of a
> > class. This will prevent breaking existing code by defining weird
> > operator void for plain type, such as int.
> >
> > Now one may ask why to bother of this.
> > Well, it would allow to implement what I call 'expression completion'
> > idiom.
>
>
> What purpose does 'expression completion' have ? How is it supposed to
> be used and what area of C++ is it supposed to fill ? I don't see any
> purpose for this complication of creating automatic type void.

In short, operators may be defined to return proxy objects without
actual evaluation of result, fe to avoid temporaries or unnecessary
calculations. But to achieve the desired result, we should be able to
deal with 'latest proxy' in a special way.
Please take a look at my answer to Andrei Iltchenko. I tried to
provide example of such purpose.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: mikup@land.ru (Mikhail Kupriyanuk)
Date: Fri, 9 Nov 2001 10:16:35 CST
Raw View
"Andrei Iltchenko" <iltchenko@yahoo.com> wrote in message news:<9sdsdo$lhq@news.nl.compuware.com>...

> > This proposal introduces some new compiler behavior while leaving all
> > the existing rules correct and not breaking any existing code ;)
>
> What you propose has the potential of not only breaking user code, but also
> the whole syntactic grammar of the language.

I really interested. Would you provide some examples of breaking user
code?

> >      1.  Require that any expression should be of type void if it is a
> > statement-expression (ie expression followed by a semicolon thus
> > representing a statement)
> >
> >        "statement-expression" :-  "expression" ";"
>
> Given the above definition of what you call an 'statement-expression' and
> the current definition of the 'expression-statement' production, which is
>     expression-statement:
>         expression opt ;
> What would the following sequence of tokens represent?
> i;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> Whould that be an expression or a statement or both?

According to grammar, it is (rewritten for clarity)

i;
;
;
;
... and so on...

ie a "statement-expression" i; followed by a bunch of empty statements
;

> The language defines the 'jump-statement' production as:
>     jump-statement:
>        continue;
>        break;
>        goto identifier;
>        return expression opt ;
>
> Now consider the jump-statement from the body of the function called 'foo':
> int  foo()
> {   return  5;   }

Good example. In this case "5" is of type int and this very function
will not be affected by operator void in any way. But there's other
function

void foo1()
{   return 5;   }

> With your definition of your 'statement-expression' the above definition
> would always be ill-formed, for a semicolon to complete the return statement
> would always be missing.
>
> By the way did you think of what precedence the new 'statement-expression'
> should have, in case you want declarations like this 'int   i = 5;' to make
> sense?
>
>
> >      2.  If the result of such expression is not of type void, then
> > operator void is called to cast the type to type void.
> >
> >      3.  If the type has no operator void defined, an
> > automatically-generated operator void is used. This compiler's
> > operator void is required to have a 'do nothing' semantics.
> >
> >      4.  It might be useful to require operator void to be member of a
> > class. This will prevent breaking existing code by defining weird
> > operator void for plain type, such as int.
> >
> > Now one may ask why to bother of this.
> > Well, it would allow to implement what I call 'expression completion'
> > idiom. Expression may contain some kind of 'lazy evaluation'
> > semantics.
>
> Can you give some examples of your 'expression completion' idiom and the
> 'lazy evaluation' semantics?

Consider statements

    a = b*c;
    &#1089; = (a-b) * (c-d);
    b && (c = d) || (c = a);

when all the variables are of complex type, say large matrices. We
might want to avoid temporaries, might we not? ;) For the sake of
efficiency, we might define operators +, -, =, ==, &&, || on matrices
in a special way. For example, operator+  returns 'proxy' object
whithout carrying necessary computations. This 'proxy' object is a
simple structure with three fields: two pointers to addends and
indicator of what to do with them, in this case int field containing
some 'plus' constant. Doing this way, we finally get 'proxy1' returned
by operator= in first statement:

proxy1: {pointer to a; '=' indicator; pointer to proxy;}
proxy:  {pointer to b; '*' indicator; pointer to c;}

But now we want our expression evaluated, right? There's no more
opportunities to delay the job. We want just a assigned b*c. So we
define operator void for 'proxy' type, compiler kindly applies it to
proxy1 object and voila! Code in proxy::operator void parses the tree
of proxies and gracefully fills matrix a with right values.

Examples are rather basic, but I hope you got the idea.

> > I consider proposed operator void as the best place to
> > carry out all the delayed job. Without being able to 'complete'
> > evaluation of expression, one ends up with giving exactly that meaning
> > to operator=.
> > This is evil in two ways:
> >   1) user is forced to assign the result
> >   2) expression may contain assignment in some part of it. In this
> > case premature evaluation would surely lead to inefficiency.
> > Generally speaking, the problem raises from giving special meaning to
> > regular operator, which is not unique in any other way.

> Give examples of well-formed C++ code that suffers from the problem you
> found!

Yes, sir! :)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: mikup@land.ru (Mikhail Kupriyanuk)
Date: Fri, 9 Nov 2001 23:39:02 GMT
Raw View
Dietmar Kuehl <dietmar_kuehl@yahoo.com> wrote in message news:<3BE9DB86.8020305@yahoo.com>...

> > Well, it would allow to implement what I call 'expression completion'
> > idiom. Expression may contain some kind of 'lazy evaluation'
> > semantics. I consider proposed operator void as the best place to
> > carry out all the delayed job. Without being able to 'complete'
> > evaluation of expression, one ends up with giving exactly that meaning
> > to operator=.
>
>
> I'd rather say that this something implemented in the destructor an
> appropriate type... Also, you might want to have a look at expression
> templates.

As it seems to me, implementing 'completion' in destructor may cause
dependance between statements. For example

{
      a = (b = c+d) ? (a*c) : (a+c);      //1
      ...                                            //here some more
statements
      a = d;                                      //2
}

If I got your idea, operator= in this example should return object of
special type. When this object leaves the scope, it will be destroyed,
and actual work will be carried out in the destructor.
But what value gets a in the above example? According to my
understanding of Standard :) it's hard to guarrantie desired result a
== d.
By the way, I looked at expression templates :) and it seems
promising. May be you could point me more specifically, to what I
might want to look ;) I've played with Blitz and Lambda library.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Heinz Ozwirk" <wansor42.NOSPAM@gmx.de>
Date: Sat, 10 Nov 2001 16:17:20 GMT
Raw View
"Mikhail Kupriyanuk" <mikup@land.ru> schrieb im Newsbeitrag
news:69ed2810.0111090248.5004a313@posting.google.com...
> "Andrei Iltchenko" <iltchenko@yahoo.com> wrote in message
news:<9sdsdo$lhq@news.nl.compuware.com>...
> Consider statements
>
>     a = b*c;
>     &#1089; = (a-b) * (c-d);
>     b && (c = d) || (c = a);

An implicit void (or better evaluate) operator as you suggested it doesn't
help. What about statements like

    x = (a=b*c, (a-b)*(c-d));

? How would you implement all the side effects that might happen? And what
about something like

    a+b;

? If you have lazy evaluation, there is now reason to evaluate such an
expression, but your 'proposal' would result in a very expansive no-op.

And you don't need an operator like that. There are lots of lazy evaluation
implementations around, that do very well without it. All you have to do, is
add a constructor to your objects, that accept a proxy and evaluate it. If
you'd do a really good job, you'd also supply an assignment operator, that
evaluates the expression proxy and assigns it.

Regards
    Heinz


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]