www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - if-expressions

reply "Bent Rasmussen" <incredibleshrinkingsphere gmail.com> writes:
I've been away from D for quite a while, but am anxious to get back and use 
the new features.

Reading the newsgroup to catch up a little, I remembered a feature of 
another language (haXe) I've been using for some light-weight work. It has 
the nice property that `if´ is an expression. So I was wondering if this 
would be nice in D as well...

int lim(int x, int a, int b)
{
    return if (x < a)
        a
    else if (x > b)
        b
    else
        x;
}

But it could also be written

int lim(int x, int a, int b)
{
    return x < a ?
        a
    : x > b ?
        b
    :
        x;
}

The question is if very nested ?: expressions will look very readable, in 
isolation and compared to if's.

I've found if-expressions to be changing my coding style and making my code 
cleaner and a lot more readable. The same goes for switch-expressions. Many 
functions have turned into pure expressions with just one point of return.

I'll try and recode some libraries using ?: expressions to begin with and 
see how it shapes up visually.

If this all sounds stupid, be gentle, I'm just returning to the D game 
again. :-)

Regards
Bent
May 28 2007
next sibling parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Bent Rasmussen wrote:
 [...]
 int lim(int x, int a, int b)
 {
    return if (x < a)
        a
    else if (x > b)
        b
    else
        x;
 }
 [...]

The advantage of having a statement-form of 'if' is that it creates a scope (expressions never create a scope). Also, if allows you declare a variable in the condition, which is also not possible in expressions. See if your other languages can do that. ;) Dave
May 28 2007
parent "Bent Rasmussen" <incredibleshrinkingsphere gmail.com> writes:
"David B. Held" <dheld codelogicconsulting.com> wrote in message 
news:f3e2fn$2h7$1 digitalmars.com...
 The advantage of having a statement-form of 'if' is that it creates a 
 scope (expressions never create a scope).  Also, if allows you declare a 
 variable in the condition, which is also not possible in expressions. See 
 if your other languages can do that. ;)

You mean something like this? :-) public static function mapPartial<S,T>(f: S -> Option<T>, s: Stream<S>): Stream<T> { return if (empty(s)) znone else { var e = f(hd(s)); if (Options.empty(e)) mapPartial(f,tl(s)) else some(Options.get(e),callback(mapPartial,f,tl(s))); } } No variable in the condition though. But thinking about it some more, this would be a very disruptive change for existing D programs, so it would be better to just try and use ?:. R. Bent
May 28 2007
prev sibling next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Bent Rasmussen wrote:
 I've been away from D for quite a while, but am anxious to get back and 
 use the new features.
 
 Reading the newsgroup to catch up a little, I remembered a feature of 
 another language (haXe) I've been using for some light-weight work. It 
 has the nice property that `if´ is an expression. So I was wondering if 
 this would be nice in D as well...
 
 int lim(int x, int a, int b)
 {
    return if (x < a)
        a
    else if (x > b)
        b
    else
        x;
 }

Or Ruby: # return if x < a then a # elsif x > b then b # else x # end
 But it could also be written
 
 int lim(int x, int a, int b)
 {
    return x < a ?
        a
    : x > b ?
        b
    :
        x;
 }
 
 The question is if very nested ?: expressions will look very readable, 
 in isolation and compared to if's.

I find myself using this from time to time, and the readability goes hand-in-hand with layout. I tend to write them closer to this: # return # x < a # ? a # : x > b # ? b # : x # ; So that the "choice" operators '?' and ':' are at the beginnings of lines. This makes it trivial for me to pick out what I care about when re-reading code.
 I've found if-expressions to be changing my coding style and making my 
 code cleaner and a lot more readable. The same goes for 
 switch-expressions. Many functions have turned into pure expressions 
 with just one point of return.
 
 I'll try and recode some libraries using ?: expressions to begin with 
 and see how it shapes up visually.
 
 If this all sounds stupid, be gentle, I'm just returning to the D game 
 again. :-)
 
 Regards
 Bent
 

I'm still neutral on if-expressions, although maybe a sub-syntax to enable them would be useful. What I /am/ quite fond of, is expression modifiers as if's (and others). Things like: parseLine unless /^$/ (Where 'unless' is Ruby's equivelant to if(!...).) Of course, the Ruby manual warns against the kinds of craziness that abuse of these kind of features can lead to. Imagine the poor maintenance programmer who comes along and finds lots of: # while artist = nextArtist # (artist.quick_name = nick) if nick = db.alias(artist) # end unless nicknames == "no" o_O`` (Slightly further barf'ing of an example from the Ruby docs.) It might really just be too much for a native/static language such as D. These are the sort of things that I don't imagine play well at all outside of a managed/VM environment. -- Chris Nicholson-Sauls
May 28 2007
parent Leandro Lucarella <llucax gmail.com> writes:
Chris Nicholson-Sauls, el 28 de mayo a las 04:04 me escribiste:
 Bent Rasmussen wrote:
I've been away from D for quite a while, but am anxious to get back and use the
new features.
Reading the newsgroup to catch up a little, I remembered a feature of another
language (haXe) I've been using for some light-weight work. It has the nice
property that 
`if´ is an expression. So I was wondering if this would be nice in D as well...
int lim(int x, int a, int b)
{
   return if (x < a)
       a
   else if (x > b)
       b
   else
       x;
}

Or Ruby: # return if x < a then a # elsif x > b then b # else x # end

On Python (>= 2.5): return a if x < a else \ b if x > b else x -- LUCA - Leandro Lucarella - Usando Debian GNU/Linux Sid - GNU Generation ------------------------------------------------------------------------ E-Mail / JID: luca lugmen.org.ar GPG Fingerprint: D9E1 4545 0F4B 7928 E82C 375D 4B02 0FE0 B08B 4FB2 GPG Key: gpg --keyserver pks.lugmen.org.ar --recv-keys B08B4FB2 ------------------------------------------------------------------------ - i bet microsoft's developers were on diet when they had to do win95 - microsoft has developers?
May 31 2007
prev sibling next sibling parent sambeau <no_spam_sambeau mac.com> writes:
Bent Rasmussen Wrote:

 I remembered a feature of 
 another language (haXe) I've been using for some light-weight work. It has 
 the nice property that `if´ is an expression. So I was wondering if this 
 would be nice in D as well...

</lurk> I have been writing/using a web scripting language for the past 5 years that makes great use of this feature. It (and the complementary 'for' construct) are really useful. I suspect they could have real use in D's compile time templates. As web scripting is essentially just fancy macros (text goes in - text with tags goes out) I wrote 'Basil' a simple template concatenator. It can do things like: xs = {1 2 3 4 5} <ul> result = for (x in xs) { <li>x</li> } </ul> (returns: "<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul> and pluralize = if(n ne 1) {{s}} As everything is a string (eg {..}) and everything returns a string and all strings can be evaluated it makes for some interesting design patterns. In places it is almost Lisp-like. I have had thoughts about trying it out as a macro language for other languages. It so far generates HTML and SQL neatly enough. Why not C/++/D?.. <lurk>
May 28 2007
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Bent Rasmussen wrote:
 ...
 int lim(int x, int a, int b)
 {
    return if (x < a)
        a
    else if (x > b)
        b
    else
        x;
 }
 ...
 
 Regards
 Bent

I've always liked this feature in languages that have it. It was one of those "eureka!" moments when I first saw it in Nemerle. Vote++; Incidentally, I don't think adding this would be very disruptive at all. if statements can't show up in expressions, so it wouldn't interfere with any existing valid code. The only thing I think that would be really weird is setting the "result" of the statement. In the case of multiple statements, you need a way to set the result. Maybe return or break could be used :) In any case, it's something I'd definitely like to see in D. Hell, I'd also like to see this: double[] as = [1.,2.,3.,4.,5.]; double[] bs = foreach(a;as) a*a; List comprehensions would be cooler still, but I'm not holding my breath on that one :P -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 28 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:f3g2kl$2tj7$1 digitalmars.com...
 In any case, it's something I'd definitely like to see in D.  Hell, I'd
 also like to see this:

 double[] as = [1.,2.,3.,4.,5.];
 double[] bs = foreach(a;as) a*a;

That looks like it could be done with array operations (defined, but not implemented): double[] as = [1, 2, 3, 4, 5]; double[] bs = as[] * as[]; // or maybe as * as
May 28 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Jarrett Billingsley wrote:
 "Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
 news:f3g2kl$2tj7$1 digitalmars.com...
 In any case, it's something I'd definitely like to see in D.  Hell, I'd
 also like to see this:

 double[] as = [1.,2.,3.,4.,5.];
 double[] bs = foreach(a;as) a*a;

That looks like it could be done with array operations (defined, but not implemented): double[] as = [1, 2, 3, 4, 5]; double[] bs = as[] * as[]; // or maybe as * as

Well, in a way, this is an explicit form of array ops with the advantage that it would work for any type with opApply :) -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 28 2007
prev sibling parent reply Leandro Lucarella <llucax gmail.com> writes:
Daniel Keep, el 29 de mayo a las 12:19 me escribiste:
 double[] as = [1.,2.,3.,4.,5.];
 double[] bs = foreach(a;as) a*a;
 
 List comprehensions would be cooler still, but I'm not holding my breath
 on that one :P

More pythonic: double[] bs = a * a foreach(a; as) if (a % 2); would give you filtering too (leaving bs = [1.0, 9.0, 25.0]) =) -- LUCA - Leandro Lucarella - Usando Debian GNU/Linux Sid - GNU Generation ------------------------------------------------------------------------ E-Mail / JID: luca lugmen.org.ar GPG Fingerprint: D9E1 4545 0F4B 7928 E82C 375D 4B02 0FE0 B08B 4FB2 GPG Key: gpg --keyserver pks.lugmen.org.ar --recv-keys B08B4FB2 ------------------------------------------------------------------------ Ambition makes you look pretty ugly
May 31 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Leandro Lucarella wrote:
 Daniel Keep, el 29 de mayo a las 12:19 me escribiste:
 double[] as = [1.,2.,3.,4.,5.];
 double[] bs = foreach(a;as) a*a;

 List comprehensions would be cooler still, but I'm not holding my breath
 on that one :P

More pythonic: double[] bs = a * a foreach(a; as) if (a % 2); would give you filtering too (leaving bs = [1.0, 9.0, 25.0]) =)

Problem with that one is that it's ambiguous. If we pretend that the "double[]" isn't there (for the sake of argument), then it could legitimately mean: (bs = a * a) foreach(a; as) if (a % 2); bs = (a * a) foreach(a; as) if (a % 2); bs = a * (a) foreach(a; as) if (a % 2); (bs = a * (a) foreach(a; as)) if (a % 2); Which is one reason why I'm not a big fan of postfix keywords :P -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 31 2007
parent reply Leandro Lucarella <llucax gmail.com> writes:
Daniel Keep, el  1 de junio a las 02:44 me escribiste:
 Leandro Lucarella wrote:
 Daniel Keep, el 29 de mayo a las 12:19 me escribiste:
 double[] as = [1.,2.,3.,4.,5.];
 double[] bs = foreach(a;as) a*a;

 List comprehensions would be cooler still, but I'm not holding my breath
 on that one :P

More pythonic: double[] bs = a * a foreach(a; as) if (a % 2); would give you filtering too (leaving bs = [1.0, 9.0, 25.0]) =)

Problem with that one is that it's ambiguous. If we pretend that the "double[]" isn't there (for the sake of argument), then it could legitimately mean: (bs = a * a) foreach(a; as) if (a % 2); bs = (a * a) foreach(a; as) if (a % 2); bs = a * (a) foreach(a; as) if (a % 2); (bs = a * (a) foreach(a; as)) if (a % 2); Which is one reason why I'm not a big fan of postfix keywords :P

it's a question of precedence, just like bs = a * a, which could mean (bs = a) * a or bs = (a * a). Python use that syntax (bs = a * a for a in as if a % 2) and it's not ambiguous. The last varian is not possible because (in python) there's no "expression" if without an else (and there is no possible else in "expression" for). -- LUCA - Leandro Lucarella - Usando Debian GNU/Linux Sid - GNU Generation ------------------------------------------------------------------------ E-Mail / JID: luca lugmen.org.ar GPG Fingerprint: D9E1 4545 0F4B 7928 E82C 375D 4B02 0FE0 B08B 4FB2 GPG Key: gpg --keyserver pks.lugmen.org.ar --recv-keys B08B4FB2 ------------------------------------------------------------------------ Every day 21 new born babies will be given to the wrong parents
May 31 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Leandro Lucarella wrote:
 Daniel Keep, el  1 de junio a las 02:44 me escribiste:
 
Leandro Lucarella wrote:

Daniel Keep, el 29 de mayo a las 12:19 me escribiste:

double[] as = [1.,2.,3.,4.,5.];
double[] bs = foreach(a;as) a*a;

List comprehensions would be cooler still, but I'm not holding my breath
on that one :P

More pythonic: double[] bs = a * a foreach(a; as) if (a % 2); would give you filtering too (leaving bs = [1.0, 9.0, 25.0]) =)

Problem with that one is that it's ambiguous. If we pretend that the "double[]" isn't there (for the sake of argument), then it could legitimately mean: (bs = a * a) foreach(a; as) if (a % 2); bs = (a * a) foreach(a; as) if (a % 2); bs = a * (a) foreach(a; as) if (a % 2); (bs = a * (a) foreach(a; as)) if (a % 2); Which is one reason why I'm not a big fan of postfix keywords :P

it's a question of precedence, just like bs = a * a, which could mean (bs = a) * a or bs = (a * a). Python use that syntax (bs = a * a for a in as if a % 2) and it's not ambiguous. The last varian is not possible because (in python) there's no "expression" if without an else (and there is no possible else in "expression" for).

Note that, in Python, assignment is not an expression, it's a statement. This is why the above is not ambiguous. Also note that Python has two forms of this concept: List comprehensions and generator expressions. A list comprehension looks like this: [a * a for a in as if a % 2] Note the surrounding brackets. A list comprehension is an expression that evaluates to a list (the Python equivalent of a vector). It computes all of the elements when the expression is evaluated. A generator expression looks just like that, but without the brackets (or with regular parentheses, if you need that additional clarity). (a * a for a in as if a % 2) A generator expression evaluates to a particular kind of object called a generator, which can be iterated over. The elements of the generator are computed lazily, as it is iterated over. If 'as' is a very large sequence, this can drastically reduce memory usage. This also implies that you cannot index a generator as you can a list. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
May 31 2007
parent "Bent Rasmussen" <incredibleshrinkingsphere gmail.com> writes:
In light of these suggestions, let me emphatically repeat: I retract my 
proposal! ;-)

R, Bent

"Kirk McDonald" <kirklin.mcdonald gmail.com> wrote in message 
news:f3n97d$1s4o$1 digitalmars.com...
 Leandro Lucarella wrote:
 Daniel Keep, el  1 de junio a las 02:44 me escribiste:

Leandro Lucarella wrote:

Daniel Keep, el 29 de mayo a las 12:19 me escribiste:

double[] as = [1.,2.,3.,4.,5.];
double[] bs = foreach(a;as) a*a;

List comprehensions would be cooler still, but I'm not holding my 
breath
on that one :P

More pythonic: double[] bs = a * a foreach(a; as) if (a % 2); would give you filtering too (leaving bs = [1.0, 9.0, 25.0]) =)

Problem with that one is that it's ambiguous. If we pretend that the "double[]" isn't there (for the sake of argument), then it could legitimately mean: (bs = a * a) foreach(a; as) if (a % 2); bs = (a * a) foreach(a; as) if (a % 2); bs = a * (a) foreach(a; as) if (a % 2); (bs = a * (a) foreach(a; as)) if (a % 2); Which is one reason why I'm not a big fan of postfix keywords :P

it's a question of precedence, just like bs = a * a, which could mean (bs = a) * a or bs = (a * a). Python use that syntax (bs = a * a for a in as if a % 2) and it's not ambiguous. The last varian is not possible because (in python) there's no "expression" if without an else (and there is no possible else in "expression" for).

Note that, in Python, assignment is not an expression, it's a statement. This is why the above is not ambiguous. Also note that Python has two forms of this concept: List comprehensions and generator expressions. A list comprehension looks like this: [a * a for a in as if a % 2] Note the surrounding brackets. A list comprehension is an expression that evaluates to a list (the Python equivalent of a vector). It computes all of the elements when the expression is evaluated. A generator expression looks just like that, but without the brackets (or with regular parentheses, if you need that additional clarity). (a * a for a in as if a % 2) A generator expression evaluates to a particular kind of object called a generator, which can be iterated over. The elements of the generator are computed lazily, as it is iterated over. If 'as' is a very large sequence, this can drastically reduce memory usage. This also implies that you cannot index a generator as you can a list. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org

May 31 2007
prev sibling parent Charles D Hixson <charleshixsn earthlink.net> writes:
Bent Rasmussen wrote:
 I've been away from D for quite a while, but am anxious to get back and 
 use the new features.
 
 Reading the newsgroup to catch up a little, I remembered a feature of 
 another language (haXe) I've been using for some light-weight work. It 
 has the nice property that `if´ is an expression. So I was wondering if 
 this would be nice in D as well...
 
 int lim(int x, int a, int b)
 {
    return if (x < a)
        a
    else if (x > b)
        b
    else
        x;
 }
 ...
 Regards
 Bent
 

This is a feature that sounds like it *should* be useful, but which I never seem to use in languages that have it. I'll use the short form (a ? b : c) in very simple expressions, but even there I won't nest the expressions. I'd guess that I use select-case statements five times more frequently, but it could be 10 times more frequently, and they are a rarely used construct. Seriously, if there were a parallel-execution for-loop construction I'd probably use it more often than I use a nested if expression. (I feel that there *OUGHT* to be a parallel execution for-loop expression, which really means a for-loop where the different iterations can be run in random order and unsynchronized, but which will all be completed by the time the end of the loop is reached. That's what I wanted foreach to mean.)
Oct 27 2007