Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional "[]" syntax for std.range.iota too #9985

Open
dlangBugzillaToGithub opened this issue Jun 24, 2013 · 8 comments
Open

Optional "[]" syntax for std.range.iota too #9985

dlangBugzillaToGithub opened this issue Jun 24, 2013 · 8 comments

Comments

@dlangBugzillaToGithub
Copy link

bearophile_hugs reported this on 2013-06-24T14:01:52Z

Transfered from https://issues.dlang.org/show_bug.cgi?id=10466

CC List

  • hsteoh
  • joseph.wakeling
  • monarchdodra

Description

There are _many_ situations where you want to iterate on a full range of an integral value using iota, and you want the iteration variable to be of that type.

Unfortunately this doesn't iterate on the last value:

iota(ubyte.min, ubyte.max)

And this doesn't yield ubytes:

iota(ubyte.min, ubyte.max + 1)

So a simple solution comes copying from std.random.uniform, using the optional "[]" syntax:

iota!"[]"(ubyte.min, ubyte.max)
@dlangBugzillaToGithub
Copy link
Author

bearophile_hugs commented on 2013-07-25T17:12:00Z

Another use case:

auto lazy_lower_case = iota!"[]"('a', 'z');

Currently you should use this that is much less handy (and it doesn't work for other reasons):

iota('a', '{')

@dlangBugzillaToGithub
Copy link
Author

hsteoh commented on 2013-08-25T14:41:32Z

I like this idea, though there are some corner cases we need to clarify, namely, what should iota!"(]"(0.0, 1.0, 0.3) and iota!"()"(0.0, 1.0, 0.3) do?

@dlangBugzillaToGithub
Copy link
Author

bearophile_hugs commented on 2013-08-25T15:23:48Z

(In reply to comment #2)
> I like this idea, though there are some corner cases we need to clarify,
> namely, what should iota!"(]"(0.0, 1.0, 0.3) and iota!"()"(0.0, 1.0, 0.3) do?

I don't use iota with floating point arguments, it's too much tricky. I prefer to write code that doesn't make my head hurt trying to understand its exact semantics months later.

So my first answer is: disallow FP types for iota(). I know this probably will not happen, so let's see. This is what the arange() function of the Python good numpy library gives for those intervals:

>>> from numpy import arange
>>> arange(0.0, 1.0, 0.3)
array([ 0. ,  0.3,  0.6,  0.9])
>>> arange(0.0, 1.0, 0.3)
array([ 0. ,  0.3,  0.6,  0.9])


So I presume your iotas should give:

iota!"(]"(0.0, 1.0, 0.3)
==>
[0.3; 0.6; 0.9]

iota!"()"(0.0, 1.0, 0.3)
==>
[0.3; 0.6; 0.9]

@dlangBugzillaToGithub
Copy link
Author

hsteoh commented on 2013-08-25T19:24:55Z

Hmm, iota with FP gets tricky, because, for example, 0.1 does not have an exact representation in floating-point. So if you write iota(0.0, 1.0, 0.1), it's unclear whether 1.0 will be included or not (for example, you may end up with 0.999999998 and it gets included, or it may end up with 1.0000001 and get excluded).

One example given in the python docs (http://docs.python.org/3/tutorial/floatingpoint.html) is that 0.1 + 0.1 + 0.1 != 0.3, because neither 0.1 nor 0.3 have exact representation in FP. So if you write iota(0.1, 0.3, ...) you might get surprised by the results. Which makes iota!"[]" and iota!"()" unreliable when used with FP. :-(

Similar issues exist if we implement issue #10762, if the user-defined type supports ++ and -- or +=, but does not have exact semantics.

@dlangBugzillaToGithub
Copy link
Author

bearophile_hugs commented on 2013-08-25T19:46:49Z

(In reply to comment #4)

> Which makes iota!"[]" and iota!"()" unreliable when used with FP. :-(

If you want to keep things simpler and you prefer a safer enhancement (that doesn't forbid future enhancements to support FP) and you want to allow the "[]" syntax only for integral types (including in future BigInt), this is OK for me :-)

@dlangBugzillaToGithub
Copy link
Author

joseph.wakeling commented on 2013-08-31T00:34:59Z

(In reply to comment #4)
> Hmm, iota with FP gets tricky, because, for example, 0.1 does not have an exact
> representation in floating-point. So if you write iota(0.0, 1.0, 0.1), it's
> unclear whether 1.0 will be included or not (for example, you may end up with
> 0.999999998 and it gets included, or it may end up with 1.0000001 and get
> excluded).

Surely that should be a case of, "use with FP at own risk".  There are cases where it might be useful, but as with all things, you need to understand the possibility of rounding error.

I got bitten rather amusingly by such an example where I was doing a for () loop across [0, 1] in 0.1 increments.  GDC and LDC can handle that, DMD couldn't, and I had to switch to increments that were negative powers of 2.  If you can trust the user to implement a for () loop correctly, you can trust them to do the same with iota().

Bottom line -- iota() currently does allow FP numbers and excluding them would be a breaking change.

@dlangBugzillaToGithub
Copy link
Author

bearophile_hugs commented on 2013-08-31T03:25:36Z

(In reply to comment #6)

> Bottom line -- iota() currently does allow FP numbers and excluding them would
> be a breaking change.

I understand the general meaning of your words, and I could agree, but at the moment there is no D code around shaped as "iota!"(]"(0.0, 1.0, 0.3)", so formally there is no breaking. A code breaking change is when code that used to work suddenly stops working or silently has a different semantics.

@dlangBugzillaToGithub
Copy link
Author

joseph.wakeling commented on 2013-08-31T12:37:42Z

(In reply to comment #7)
> I understand the general meaning of your words, and I could agree, but at the
> moment there is no D code around shaped as "iota!"(]"(0.0, 1.0, 0.3)", so
> formally there is no breaking. A code breaking change is when code that used to
> work suddenly stops working or silently has a different semantics.

No, but there is D code shaped around iota(0.0, 1.0, 0.3) which is semantically identical to iota!"[)"(0.0, 1.0, 0.3), which is part of the proposal.

So, if there is going to be any "choice of boundary conditions" generalization of iota, it should work as a seamless generalization of all the behaviour it currently supports -- which includes both integral and floating-point types.

@LightBender LightBender removed the P4 label Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants