February 09, 2011
On 2/9/11 7:54 AM, Nick Sabalausky wrote:
> "spir"<denis.spir@gmail.com>  wrote in message
> news:mailman.1423.1297254917.4748.digitalmars-d@puremagic.com...
>>
>> PS: your proposal would also logically allow, I guess, expressions like (n
>> in min..max). Would love it.
>>
>
> Unfortunately, not unless "in" was changed to allow "{expr} in {range}". And
> from prior discussions of "in", I seem to remember Walter and Andrei are
> strongly against allowing "in" to be used to check for element values rather
> than just AA keys.
>
> But Andrei did recently propose an "any", IIRC, that would allow something
> like what you're suggesting.

a in iota(min, max) is a O(1) operation so it could be allowed.

Andrei

February 09, 2011
On 2/9/11 7:46 AM, Nick Sabalausky wrote:
> "spir"<denis.spir@gmail.com>  wrote in message
> news:mailman.1422.1297254724.4748.digitalmars-d@puremagic.com...
>>
>> Side-question: what is actually 1..5 as of now for a thing? Or is it
>> conceptually "unconstructed" by rewriting to (probably) an ordinary for
>> loop? Anyway, the point above applies to language-side semantics, whatever
>> optimisation may happen.
>>
>
> AIUI: Syntactically, it doesn't exist at all, at least not by itself. It's
> just part of one of the foreach syntaxes:
>
>    'foreach' '(' {declaration list} ';' {expression} '..' {expression} ')'
>
> and also part of one of the slice syntaxes:
>
>    (from the docs:)
>    PostfixExpression [ AssignExpression .. AssignExpression ]
>
> Although it's possible I've understood it wrong.
>
> Don't have a clue how it's handled beyond that though.

Indeed, a..b is just punctuation in the two grammatical constructs you mentioned.

Your proposal has indeed been made a couple of times, first probably by bearophile - but then what did bearophile /not/ propose? (Meaning this in good fun.) I think it would be okay to move iota into druntime and enact the rewrite. But this would improve the language by such a small iota...

I buy the orthogonality argument as much as you do. foreach is not orthogonal because it is a short form of for, which is not orthogonal because it is a short form of while, which is not orthogonal because it is a short form of a scope with if/goto at the top.

If a..b would be rewritten into iota(a, b) that would still be non-orthogonal because one could express one thing in two ways. Ironically, it's more orthogonal to leave things as they are: you have iota(a, b) as the general concept and you have a..b as punctuation in two grammatical constructs.

But the most important question is: if the rewrite were done, to what extent would that improve your use of the language? Integral intervals do occur outside foreach and slices, but quite infrequently. In those cases you'd gain by replacing iota(a, b) with a..b. Is this significant?


Andrei
February 09, 2011
On 02/09/2011 01:54 PM, Nick Sabalausky wrote:
> "spir"<denis.spir@gmail.com>  wrote in message
> news:mailman.1423.1297254917.4748.digitalmars-d@puremagic.com...
>>
>> PS: your proposal would also logically allow, I guess, expressions like (n
>> in min..max). Would love it.
>>
>
> Unfortunately, not unless "in" was changed to allow "{expr} in {range}". And
> from prior discussions of "in", I seem to remember Walter and Andrei are
> strongly against allowing "in" to be used to check for element values rather
> than just AA keys.
>
> But Andrei did recently propose an "any", IIRC, that would allow something
> like what you're suggesting.

IIRC, they did not argue against it for ranges specifically, but for it beeing O(n) for conceptually sequential collections like plain arrays, unlike for AAs, thus misleading in terms of efficiency. But 'in' is O(1) for an interval ;-) So, there is no reason to disallow it, instead such a feature would be both obvious & useful.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

February 09, 2011
Andrei:

> But the most important question is: if the rewrite were done, to what extent would that improve your use of the language? Integral intervals do occur outside foreach and slices, but quite infrequently. In those cases you'd gain by replacing iota(a, b) with a..b. Is this significant?<

I can list you why I think an interval syntax is better, but at the end you need to judge values:

- The basic range syntax is already present in two different situations in the language, for slices and foreach (switch-case statement use the dot-dot syntax for a related but different purpose). So D programmers don't need to learn a new syntax, the cognitive cost is probably negative.

- The 1 .. 5 syntax is present in math too (even if it often means a set closed on the right too).

- There is no need to learn to use a function with a weird syntax like iota, coming from APL. This makes Phobos and learning D a bit simpler.

- Both 1..5 and iota(1,5) are able to support the "in" operator. This is good because D doesn't support the a<X<b Python syntax.  X in a..b will mean a<=X<b.

- If the compiler front-end becomes aware of the interval syntax, it is able to perform "3 in 1..10" at compile-time too, simplifying sub-expressions even when they are inside other run-time expressions.

- With the interval syntax there is no need to import std.range, that's necessary for iota().

- the a..b syntax is shorter and a bit less noisy:  array(1..5) compared to array(iota(1,5)).

- The a..b syntax is extendible to cover the third stride argument of iota(). I suggest a..b:c  (The stride syntax is later usable for arrays too if the stride is a compile-time constant). Python shows several nice usages of the stride argument.

- Currently foreach(i; retro(iota(...))) or even foreach(i; iota(...)) are not as fast as foreach(i; ...). I hope this interval syntax will help DMD digest a lazy interval more efficiently.

- Interesting point, to translate this to interval syntax: iota(1.,-5.) it becomes 1...5. that's a mess. You need zeros:  1.0 .. 5.0

- Another interesting point, currently the semantics of iota() and the interval in foreach are not the same, only the second loop here raises an exception:

import std.stdio, std.range;
void main() {
    foreach (x; 1 .. -5)
        writeln(x);
    foreach (x; iota(1, -5))
        writeln(x);
}

In my opinion iota() semantics here must be the same as the foreach interval, and yield an empty iterable with no errors:
http://d.puremagic.com/issues/show_bug.cgi?id=4603


I like the interval literal syntax for static things too, example:
http://d.puremagic.com/issues/show_bug.cgi?id=4085
static foreach (x; 1 .. -5)

A first class literal syntax in D (typeid(typeof(1..5)) gives a new type) may become useful for slices too in objects/structs, this is Python 2.6 code:


class Foo(object):
    def __getitem__(self, key):
        print key
f = Foo()
f[1:2]


Output:
slice(1, 2, None)

Bye,
bearophile
February 09, 2011
Am 09.02.2011 19:54, schrieb bearophile:
> 
> - Both 1..5 and iota(1,5) are able to support the "in" operator. This is good because D doesn't support the a<X<b Python syntax.  X in a..b will mean a<=X<b.
> 

Don't know about Python, but in D this will only be true if X is an integer.
I guess 1<X<4 is true for X=1.5 in Python.. it would certainly not be true for X
in 1..4 in D.
Also using X in 1..4 is in D is pretty bad if you just want to check if 1<X<4
(or even more when checking 1<X<100) because it has a much higher overhead -
even though it may be technically O(1) because 4 or 100 is a constant) than just
doing two comparisons. So IMHO using X in 1..4 or x in iota(1,4) should not be
encouraged. (X in [1,3,4,8] is different.)
Of course the compiler could transform X in 1..4 to X>1 && X<4, but... I don't
think it's a good idea.
If this syntax is accepted, 1..4 should create a range/array containing [1,2,3]
- without addidional voodoo.

> - If the compiler front-end becomes aware of the interval syntax, it is able to perform "3 in 1..10" at compile-time too, simplifying sub-expressions even when they are inside other run-time expressions.
> 


Cheers,
- Daniel
February 09, 2011
Daniel Gibson:

> Don't know about Python, but in D this will only be true if X is an integer.
> I guess 1<X<4 is true for X=1.5 in Python.. it would certainly not be true for X
> in 1..4 in D.

You are right, the semantics is different, my silly mistake. Thank you.


> Also using X in 1..4 is in D is pretty bad if you just want to check if 1<X<4
> (or even more when checking 1<X<100) because it has a much higher overhead -
> even though it may be technically O(1) because 4 or 100 is a constant)

Even if the bounds are not constants it's not hard to perform  x in a..b  in O(1).

Bye,
bearophile
February 09, 2011
Am 09.02.2011 20:57, schrieb bearophile:
> Daniel Gibson:
> 
>> Don't know about Python, but in D this will only be true if X is an integer.
>> I guess 1<X<4 is true for X=1.5 in Python.. it would certainly not be true for X
>> in 1..4 in D.
> 
> You are right, the semantics is different, my silly mistake. Thank you.
> 
> 
>> Also using X in 1..4 is in D is pretty bad if you just want to check if 1<X<4
>> (or even more when checking 1<X<100) because it has a much higher overhead -
>> even though it may be technically O(1) because 4 or 100 is a constant)
> 
> Even if the bounds are not constants it's not hard to perform  x in a..b  in O(1).
> 

If the compiler does optimizations (=> transforms it to if( a<=x && x<b)), yes.
If a..b are handled as a generic range (just like e.g. [1, 10, 4, 7, 3, 42]) I
don't think it's as easy in constant time. Maybe when putting the range into a
hash table.. but this also has some overhead.

> Bye,
> bearophile

Cheers,
- Daniel
February 09, 2011
On 2/9/11 3:54 PM, bearophile wrote:
> - There is no need to learn to use a function with a weird syntax like iota, coming from APL. This makes Phobos and learning D a bit simpler.

I would recommend stop using "weird" names for functions. Sorry if this sounds a little harsh but the only reason I see this function is called "iota" is to demonstrate knowledge (or to sound cool). But programmers using a language don't care about whether the other programmer demonstrates knowledge behind a function name, they just want to get things done, fast.

I mean, if I want to create a range of numbers I would search "range". "iota" will never, ever come to my mind. D has to be more open to public, not only to people who programmed in APL, Go or are mathematics freaks. Guess how a range is called in Ruby? That's right, Range.

Another example: retro. The documentation says "iterates a bidirectional name backwards". Hm, where does "retro" appear in that text? If I want to iterate it backwards, or to reverse the order, the first thing I would write is reverse(range) or backwards(range), "retro" would never come to my mind.

(and no, replies like "you can always alias xxx" are not accepted :-P)
February 09, 2011
Am 09.02.2011 21:08, schrieb Ary Manzana:
> On 2/9/11 3:54 PM, bearophile wrote:
>> - There is no need to learn to use a function with a weird syntax like iota, coming from APL. This makes Phobos and learning D a bit simpler.
> 
> I would recommend stop using "weird" names for functions. Sorry if this sounds a little harsh but the only reason I see this function is called "iota" is to demonstrate knowledge (or to sound cool). But programmers using a language don't care about whether the other programmer demonstrates knowledge behind a function name, they just want to get things done, fast.
> 
> I mean, if I want to create a range of numbers I would search "range". "iota" will never, ever come to my mind. D has to be more open to public, not only to people who programmed in APL, Go or are mathematics freaks. Guess how a range is called in Ruby? That's right, Range.
> 
> Another example: retro. The documentation says "iterates a bidirectional name backwards". Hm, where does "retro" appear in that text? If I want to iterate it backwards, or to reverse the order, the first thing I would write is reverse(range) or backwards(range), "retro" would never come to my mind.
> 
> (and no, replies like "you can always alias xxx" are not accepted :-P)

I agree that iota is a bad name, but "Range" is a bad name because it's already used in D.

Cheers,
- Daniel
February 09, 2011
Ary Manzana wrote:
> On 2/9/11 3:54 PM, bearophile wrote:
>> - There is no need to learn to use a function with a weird syntax like iota, coming from APL. This makes Phobos and learning D a bit simpler.
> 
> I would recommend stop using "weird" names for functions. Sorry if this sounds a little harsh but the only reason I see this function is called "iota" is to demonstrate knowledge (or to sound cool). But programmers using a language don't care about whether the other programmer demonstrates knowledge behind a function name, they just want to get things done, fast.
> 
> I mean, if I want to create a range of numbers I would search "range". "iota" will never, ever come to my mind. D has to be more open to public, not only to people who programmed in APL, Go or are mathematics freaks. Guess how a range is called in Ruby? That's right, Range.
> 
> Another example: retro. The documentation says "iterates a bidirectional name backwards". Hm, where does "retro" appear in that text? If I want to iterate it backwards, or to reverse the order, the first thing I would write is reverse(range) or backwards(range), "retro" would never come to my mind.
> 
	Well, at least “retro” is compatible with the dictionary
signification of the word, so even though it is not the first word
that would come to mind when searching how to reverse a list, it
should be pretty self explanatory when reading existing code.

	OTOH, “iota” is not and could even be argued to be antonymous to
the dictionary meaning, which makes it all that much more difficult
to understand.

		Jerome
-- 
mailto:jeberger@free.fr
http://jeberger.free.fr
Jabber: jeberger@jabber.fr