New C operator -- would it be a good idea?

M

mike3

Hi.

I was wondering about this. I saw this posting on this site:

http://stackoverflow.com/questions/1642028/what-is-the-name-of-this-operator

where they were mentioning a fake "operator", an artifact of how the C
language is interpreted, that looked like it caused the value of a
variable to "go to" another. Namely, "x --> 0" in the code was just
"x-- > 0", giving it the appearance of having the effect of
"incrementing x toward 0". Now, I was wondering: would this be a good
idea for a new real operator for the C language? Namely, "a -->
b" (and "b <-- a") as real operators that could increment a toward b.
Or would it be pretty worthless?
 
K

Kaz Kylheku

Hi.

I was wondering about this. I saw this posting on this site:

http://stackoverflow.com/questions/1642028/what-is-the-name-of-this-operator

where they were mentioning a fake "operator", an artifact of how the C
language is interpreted, that looked like it caused the value of a
variable to "go to" another. Namely, "x --> 0" in the code was just
"x-- > 0", giving it the appearance of having the effect of
"incrementing x toward 0". Now, I was wondering: would this be a good
idea for a new real operator for the C language? Namely, "a -->
b" (and "b <-- a") as real operators that could increment a toward b.
Or would it be pretty worthless?

I can give you five reasons why not.

1. It would be worthless because using it would make your code nonportable to all
the compilers which have decided to ignore implementing such a thing.
The best feature of C is stability, and the best dialect for that is ISO C90,
(with perhaps some very judicious use of new-fangled libraries from C99 and C11.)

2. The --> and <-- syntax has an existing meaning. It is tokenized as {--}{>}
and {<}{--}. The expression a-->b is already valid C. It means (a--) > (b).
In other words, decrement a, and test whether the prior value is greater than b.
So your proposal horribly breaks the current language, making it a complete
nonstarter.

3. Not having b <-- a, you have to write something like a = (a < b) ? a + 1 : a - 1;
This is not a big deal and you can hide it behind a macro, except that it evaluates
a twice:

#define INCTOWARD(A, B) ((A) = (A) < (B) ? (A) + 1 : (A) - 1)

See? You can implement the operator in C already, just not with the syntax you want,
and with a small semantic concession. But this means that the --> operator
does not express anything which cannot be expressed already, it just makes a
small, incremental semantic improvement over the macro. A small, incremental
improvement is harder to justify. Moreover, the syntax that you want breaks
the existing syntax (point 2 above), whereas the INCTOWARD macro doesn't.

4. There is no corresponding machine instruction in any popular machine
instruction set, so you're not going to get better code by providing an inctoward
operator in the language. And even if there is a single machine instruction
for doing (A < B ? A + 1 : A - 1), a compiler just has to recognize this
syntax tree pattern, and check a few constraints and then use the
instruction. It is not strictly necessary to have a dedicated operator.
For instance, some instruction sets have a division instruction which yields both
the quotient and the modulus. Compilers recognize code like
a = b / c; d = b % c and emit just one division instruction from which the
quotient and modulus are obtained for a and d.

5. A trivial new arithmetic operator is not going to lend expressivity to the C language.
And anyway, programmers don't need C to be expressive. By and large they
need it to be a "portable assembler". If you want expressivity, you invent
another programming language and then interpret it with C, or compile it to C.
That language can easily have an A <-- B operator, which expands into
the appropriate C (with clean evaluation semantics and everything).
 
K

Keith Thompson

Scott Fluhrer said:
However, if we have a built-in 'b <-- a' operator, well, the language has to
specify exactly what the behavior is (and if it makes it
unspecified/implemented-defined or undefined, well, that means that the
programmer generally can't depend on it).
[...]

And of course we can't use that syntax for a new operator, since
b <-- a
already has a well defined meaning.

(Conceivably you could define a new "<--" operator that's 100%
compatible with all possible occurrences of "< --", but I'm skeptical
that that would be both possible and useful.)
 
B

BartC

mike3 said:
Hi.

I was wondering about this. I saw this posting on this site:

http://stackoverflow.com/questions/1642028/what-is-the-name-of-this-operator

where they were mentioning a fake "operator", an artifact of how the C
language is interpreted, that looked like it caused the value of a
variable to "go to" another. Namely, "x --> 0" in the code was just
"x-- > 0", giving it the appearance of having the effect of
"incrementing x toward 0". Now, I was wondering: would this be a good
idea for a new real operator for the C language? Namely, "a -->
b" (and "b <-- a") as real operators that could increment a toward b.
Or would it be pretty worthless?

Why do you need two versions? (Namely, --> and <--).

Do you mean the operator increments an lvalue so that it converges towards
another given value?

This can be done using:

a += sign(b-a);

where sign() returns (-1,0,1) depending on whether it's argument is
negative, zero or positive.

I doubt whether sign() is already lurking in the standard library somewhere
(a version that takes an integer argument), but if not, that sounds a far
more useful addition. And using function syntax, can also easily be added as
a user function without having to hang about a couple of decades until it's
part of the language (or, more likely, until it's not).
 
M

Malcolm McLean

בת×ריך ×™×•× ×©×œ×™×©×™, 11 בספטמבר 2012 22:33:30 UTC+1, מ×ת Bart:
I doubt whether sign() is already lurking in the standard library somewhere
It's a missing macro. min, max, PI, uniform, clamp, lerp and round should all
have been inthe original language, along with sign.
 
M

mike3

I can give you five reasons why not.

1. It would be worthless because using it would make your code nonportable to all
   the compilers which have decided to ignore implementing such a thing.
   The best feature of C is stability, and the best dialect for that is ISO C90,
   (with perhaps some very judicious use of new-fangled libraries from C99 and C11.)

So does this mean using C99, etc. is bad, then? If not, then how come
more compiler
developers would implement C99, etc. stuff and not --> if --> became a
real part of the
C language?
2. The --> and <-- syntax has an existing meaning. It is tokenized as {--}{>}
   and {<}{--}.  The expression a-->b is already valid C. It means (a--) > (b).
   In other words, decrement a, and test whether the prior value is greater than b.
   So your proposal horribly breaks the current language, making it acomplete
   nonstarter.

So make it ==> and <==.
3. Not having b <-- a, you have to write something like a = (a < b) ? a+ 1 : a - 1;
   This is not a big deal and you can hide it behind a macro, except that it evaluates
   a twice:

     #define INCTOWARD(A, B) ((A) = (A) < (B) ? (A) + 1 : (A) - 1)

   See? You can implement the operator in C already, just not with the syntax you want,
   and with a small semantic concession. But this means that the --> operator
   does not express anything which cannot be expressed already, it just makes a
   small, incremental semantic improvement over the macro. A small, incremental
   improvement is harder to justify. Moreover, the syntax that you want breaks
   the existing syntax (point 2 above), whereas the INCTOWARD macro doesn't.

True. But could the compiler optimize it better (e.g. if it's used in
a loop) if it were
a builtin?
4. There is no corresponding machine instruction in any popular machine
   instruction set, so you're not going to get better code by providing an inctoward
   operator in the language.  And even if there is a single machineinstruction
   for doing (A < B ? A + 1 : A - 1), a compiler just has to recognize this
   syntax tree pattern, and check a few constraints and then use the
   instruction. It is not strictly necessary to have a dedicated operator.
   For instance, some instruction sets have a division instruction which yields both
   the quotient and the modulus. Compilers recognize code like
   a = b / c; d = b % c and emit just one division instruction from which the
   quotient and modulus are obtained for a and d.

This is probably one of the best points against this. All other C
operators have some
kind of equivalent machine instruction on most machines, or close
enough. So yes, I'd
admit, this may be a downside.
5. A trivial new arithmetic operator is not going to lend expressivity tothe C language.
   And anyway, programmers don't need C to be expressive. By and large they
   need it to be a "portable assembler". If you want expressivity, you invent
   another programming language and then interpret it with C, or compile it to C.
   That language can easily have an A <-- B operator, which expands into
   the appropriate C (with clean evaluation semantics and everything)..

I thought it'd be kind of neat, but maybe it isn't really necessary.
I'd wonder, how
often does it come up that you need to increment one variable "toward"
another, i.e.
make one "go to" another? Though I haven't programmed a big diversity
of things,
it dosn't seem to be super often, unlike conventional increments.
 
M

mike3

That gives us Yet Another reason (beyond what Kaz and I already listed):
what exactly is the desired behavior?  Specifically, what should the
operator do if a==b initially?

My longhand version assumed one behavior (a remains the same), while Kaz's
version assumed another (a is decremented).  Which is correct?  Well,that
depends entirely on what the original programmer meant; in longhand, he can
easily select either behavior (or something else entirely if that's
appropriate).

However, if we have a built-in 'b <-- a' operator, well, the language hasto
specify exactly what the behavior is (and if it makes it
unspecified/implemented-defined or undefined, well, that means that the
programmer generally can't depend on it).

So, to that extent, this proposed built-in would have less expressiveness
than what's already in the language.

What I was thinking of was that a --> b when a == b should leave a
unchanged.
Because the idea is that with repeated application, a converges to b,
or
a "goes to" b. So when a == b, a should remain unchanged, as it is
"already
there".

However, as for this "expressiveness" issue: the question comes down
to whether
or not it'd be a good idea to have certain things made into a short-
hand, easily-
available form or not. That is, is it more _convenient_ -- does it
make things
_easier_ if we had -->. Wouldn't it be nice to know it's there if you
need it,
so you don't have to code that extra macro or whatever?

I do however, wonder in light of this point, which kind of what-to-do-
when-the-
values-are-equal behavior is used most often in actual real uses of
this operation
(written without this operat_or_, of course).
 
M

mike3

You mean, like an assignment statement?

No, more like causing the value of one to change incrementally toward
that of another (though in this case, the second "operand" was a
constant integer literal and not a variable...).
That doesn't make a lot of sense.  What's the difference
between "incrementing x toward 0" and "decrementing x toward 0",
and if there is no difference, why not?  And what's the difference
between either of them and "decrementing x toward Paris, France"?

True, my wording isn't quite right. Think about "stepping x closer to
0".
No.  a-->b already has a defined meaning.  An important consideration
for standards is not breaking existing code.

So we could use "==>" instead.
As far as I know, nothing conflicts with using :=: as an operator,
as in:
        b :=: a;
which might or might not mean to take the reciprocal of the
base-pi logarithm of each value, then swap them.  How did we
possibly get along without that?

So you've never encountered a situation in which you have to step
the value of a variable closer to that of another?

Oen situation, and the one that inspired this post, along with the
discusson on stackoverflow, is that of looping or moving between two
coordinate points. Suppose you have coordinates x0 and x1 and want to
move between them. Let x be your current position. To move in a unit
step
toward x1:

x --> x1; (or x ==> x1;)

To move the other way, toward x0:

x --> x0; (or x ==> x0;)

or, perhaps if you think of this as "backwards" movement,

x0 <-- x; (or x0 <== x;)

Note that with this, the order of x0 and x1 does not matter,
which is the point here. You don't have to swap them or check
their order or something like that in order to move x toward
one or the other. E.g. if x1 > x0 you can move toward x0
with the same operator as if x1 were < x0, regardless of the
value of x.
Please define "increment a toward b", without using the phrases
"increment toward", "decrement toward", or "crement toward" (which
I'll assume mean "a suffusion of Ankylosaurus poop") in the
definition.  What happens if a and b are equal?  What happens if b
is NaN?  (I am assuming this operator can apply to floating-point
numbers as well).  What happens if a = 1.25 and b = 1.0?  Does a
become 0.25?  (increment a toward *and possibly past* b)?  What
happens if b is +Inf (and floating-point) and a is INT_MAX (and
of type int?)

crement a toward b :)

Heh. What it means is to step a by a unit step, same size as ++
or -- (i.e. by 1), in the direction that brings the value of a
closer to the value of b, or leaves a unchanged if a == b.

I suspect it wouldn't work so well for floats, and would probably
have to be limited to integer types. Though I suppose one could
make it so that in your example if we took a --> b we'd get
a = 1.0 at the end, i.e. step by 1s, but if the result is within
1 of b, then make the result equal to b. Though what to do if a
is an integer??? Perhaps make it so that a can be stepped to within
1 of b, and then it stops there just as if a == b. Though, I wonder,
how'd we handle something like b = 1.5e+9 and b is a 32-bit float?
Step to the rounded value of 1,500,000,000? And don't forget
issues related to the binary nature of the floats... Oy, this is
a problem. Perhaps it'd be best if it required a and b to be of the
same type.

And I suspect it wouldn't be as useful for floats as for integers
unless there were some way to control the size of the step.
 
N

Nick Keighley

[the inc-toward operator]
[...]  Specifically, what should the operator do if a==b initially?

What I was thinking of was that a --> b when a == b should leave a
unchanged.
Because the idea is that with repeated application, a converges to b,
or
a "goes to" b. So when a == b, a should remain unchanged, as it is
"already
there".

However, as for this "expressiveness" issue: the question comes down
to whether
or not it'd be a good idea to have certain things made into a short-
hand, easily-
available form or not. That is, is it more _convenient_ -- does it
make things
_easier_ if we had -->. Wouldn't it be nice to know it's there if you
need it,
so you don't have to code that extra macro or whatever?

but how would you use it? With an approriate return value
this:-

for (i = 0; i < 10; i++)
do_something (i);

could be

i = 0;
while (i --> 10)
do_something (i);

but I'm not sure this buys you much.
I do however, wonder in light of this point, which kind of what-to-do-
when-the-
values-are-equal behavior is used most often in actual real uses of
this operation
(written without this operat_or_, of course.


I'm simply failign to see the point
 
B

BartC

mike3 said:
On Sep 11, 4:27 pm, (e-mail address removed) (Gordon Burditt) wrote:

So you've never encountered a situation in which you have to step
the value of a variable closer to that of another?

Hardly ever. More common is to have to choose between ++ and -- depending on
some condition known at runtime. And it's usually treated like this:

incr = cond?1:-1;

a += incr;

Not quite the same as your operator, as it doesn't check that it's reached
some limit and so stops incrementing/decrementing. But as part of a loop
that takes care of termination, it will be faster than yours. (Your operator
will anyway still need loop control to be added.)
Oen situation, and the one that inspired this post, along with the
discusson on stackoverflow, is that of looping or moving between two
coordinate points. Suppose you have coordinates x0 and x1 and want to
move between them. Let x be your current position. To move in a unit
step
toward x1:

x --> x1; (or x ==> x1;)

To move the other way, toward x0:

x --> x0; (or x ==> x0;)

or, perhaps if you think of this as "backwards" movement,

x0 <-- x; (or x0 <== x;)

It's more likely that you'd want to move between two 2D points: if you have
two points (or vectors) p and q, and want a third point r to move from p to
q, one way is:

r = p;
incr = (q-p)/nsteps; // obviously no longer C at this point

r+=incr; // repeated nsteps times

This would normally use floating point ; with integer arithmetic (discrete
pixels), then there are a bunch of other problems, because the pixel
increments will be uneven in x and y (it needs the line drawing algorithm).
That would make the use of "-->" awkward too:

r --> q; // won't work in C; q is a point

r.x --> q.x;
r.y --> q.y;

These latter two won't work, as there will be a different number of steps
for each (and r moves at 45 degree angles).
And I suspect it wouldn't be as useful for floats as for integers
unless there were some way to control the size of the step.

Actually it sounds like it could be more useful for floats, and vectors as
in my example. But inefficient compared with alternatives, because you'd
need to specify the step at each step.

It seems it ought to be part of a loop control, with having to specify what
looks like a terminating condition, and possibly a step, but without
actually having the power to break out of a loop. That means you'd need a
normal loop condition on top.
 
B

BartC

Nick Keighley said:
On Sep 11, 11:56 pm, mike3 <[email protected]> wrote:
but how would you use it? With an approriate return value
this:-

for (i = 0; i < 10; i++)
do_something (i);

could be

i = 0;
while (i --> 10)
do_something (i);

This looks like it will loop forever (more than 10 times anyway), unless the
'value' of i-->10 is neither i nor 10. It would have return 0 when it's
reached the target, and 1 otherwise.
 
M

mike3

where they were mentioning a fake "operator", an artifact of how the C





People (compiler users, compiler writers, and language standards
committees) do move towards newer language features.  But there is a
very high threshold before new features are added to the language.  Just
look at the recent discussions about adding C features to C++ or C++
features to C - this is a tough processes even when the features are of
obvious benefit to users, are already implemented by the compilers, are
familiar to many users (since many people are fluent in C /and/ C++),
and are documented in similar types of standards.

So for a nonsensical operator with poorly specified semantics, rare use
cases, and a syntax that conflicts with existing standards, I would not
be optimistic...

What would need to be specified with regards to the semantics? And I
also
proposed an alternative symbol for the operator here. But I suppose
the
ultimate problem is going to be that of "rare use case" -- and there
ain't
nothin' anyone can do about that... In other words, there doesn't
appear
to be much hope for this operator... said:
Why do you think that?  I don't know what you mean by "the" compiler
here, but many C compilers are very good at optimising, and they don't
need builtins to do it.  In this particular case, I'd expect a compiler
to produce better code with macro version - in many cases, a compiler
could hoist the initial comparison to the top of the loop, statically
identify the result of the comparison, and replace the inner loop with a
simple ++ or -- and comparison.

And in general, /if/ there were significant use cases for such a
construction, and /if/ there were significant gains to be made by
treating it specially, then compilers could include the pattern in the
pattern matching machinery and optimise specifically for it.

I was just thinking that maybe a builtin could help provide better
"hints"
to the compiler, but I guess it isn't really necessary...
No, many operators do not equate to a machine instruction on most
targets.  There are a few cpu targets that have hardware support for
things like division - a great many cannot even do a 16-bit increment in
a single instruction.  There are also many machine instructions that do
not correspond to a single C construct - the most obvious one being that
on most targets, a "comparison" operation gives flags for greater than,
less than, equal to, and combinations thereof, while in C you can only
test for one at a time.  It is up to compilers to spot patterns like "if
(a > b) { .. } else if (a < b) { ... }" and generate a single comparison.

Arguing based on target machine instructions and/or compiler
implementations is best done when you have experience of a wide range of
target architectures and of compiler functionality.

So in light of all this, is the machine-instruction argument I
originally
responded to really worth anything, then?
I just cannot see a point in this operator.  The nearest I can think of
that would actually be useful would be "if (x) x--;".

And I guess that's the biggest problem here -- there just really isn't
much point to this operator.

Oh well...
 
E

Edward A. Falk

I can give you five reasons why not.

1. It would be worthless because using it would make your code nonportable to all
the compilers which have decided to ignore implementing such a thing.
The best feature of C is stability, and the best dialect for that is ISO C90,
(with perhaps some very judicious use of new-fangled libraries from C99 and C11.)

This one alone is sufficient. C has managed to evolve into the most portable
language there is, primarily because of its stability.

(Although I wouldn't mind built-in abs(), min(), and max() functions, I admit
it's too late for even those.)
 
M

mike3

This one alone is sufficient.  C has managed to evolve into the most portable
language there is, primarily because of its stability.

Also, rarity of usage looks like another good point against this
proposal. I think
I've used pretty much every C operator there is, and yet there are
people here saying
they'd never have used this --> operator in years and years of C
programming.

I'm thinking I should probably put this one to bed...
 
G

Greg Martin

crement a toward b :)

Heh. What it means is to step a by a unit step, same size as ++
or -- (i.e. by 1), in the direction that brings the value of a
closer to the value of b, or leaves a unchanged if a == b.

If it ever came up this or some permutation would seem to work:

x < y ? --y : (x > y ? ++y : y);
 
I

Ike Naar

This one alone is sufficient. C has managed to evolve into the most portable
language there is, primarily because of its stability.
(Although I wouldn't mind built-in abs(), min(), and max() functions, I admit
it's too late for even those.)

<stdlib.h> has abs(), labs(), llabs().

<math.h> has fabs(), fmin(), fmax() for the floatingpoint types.
 
B

BartC

io_x said:
if "i" begin from 0 i-- would return 0 !> 10 so exit in the first
iteration

But "-->" operates immediately, so the first value of (i-->10) would be 1.

(Don't forget we're discussing a new, proposed "-->" operator and not "--"
followed by ">")
 
B

BartC

Ike Naar said:
<stdlib.h> has abs(), labs(), llabs().

<math.h> has fabs(), fmin(), fmax() for the floatingpoint types.

They might be built-in, but they are still just functions with all their
limitations:

o Not being able to use them in constant expressions
o Having to use different names depending on the exact type of the argument

So there's nothing to stop someone defined their own min()/max() functions,
except:

o They would not be standard
o They would need min, umin, lmin, lumin, llmin, llumin, and the same for
max. (You could probably get away with providing only long long versions,
but there would be a lot of unnecessary promotions.)

If min(), max() were operators, then that would be it; you wouldn't need
anything else, not even fmin() and fmax().
 
B

Ben Bacarisse

Greg Martin said:
[in]crement a toward b :)

Heh. What it means is to step a by a unit step, same size as ++
or -- (i.e. by 1), in the direction that brings the value of a
closer to the value of b, or leaves a unchanged if a == b.

If it ever came up this or some permutation would seem to work:

x < y ? --y : (x > y ? ++y : y);

A much more useful fictitious operator was recently discussed: the
compare operator <>. In terms of this, you'd just write

x += y <> x;
 
K

Keith Thompson

Ben Bacarisse said:
Greg Martin said:
[in]crement a toward b :)

Heh. What it means is to step a by a unit step, same size as ++
or -- (i.e. by 1), in the direction that brings the value of a
closer to the value of b, or leaves a unchanged if a == b.

If it ever came up this or some permutation would seem to work:

x < y ? --y : (x > y ? ++y : y);

A much more useful fictitious operator was recently discussed: the
compare operator <>. In terms of this, you'd just write

x += y <> x;

Perl has this operator, but spells it <=>. It's commonly referred to as
the "spaceship operator". It yields -1, 0, or 1 depending on whether
it's left operand is less than, equal to, or greater than its right
operand. (If either operator is a NaN, it yields undef, a false scalar
value distinct from 0; C doesn't have such a thing.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top