Hi everyone!
I want to talk about High proc and the way it confused me ( several times already )
The issue is that usually I use ( and as many others, I believe) High to get last index in a seq or array. It's fine. But confusion comes with ordinals.
var index = 600_000
var last = index.high # expect to see 599_999, but get the highest possible value of an ordinal
YES, I read the doc for the High and I clearly see the description about
the highest possible value of an ordinal.
But over and over again I get into this pitfall cause logically I don't get why in a heck I get 9223372036854775807 for 600_000.high It's just not intuitive :)
high(int) # get the highest value for ordinal type int, I get it, elegant and smart, agree
INT_MAX # something like that I used in C#, not that smart as example above, but ok
high(600_000) # confusion, returns 9223372036854775807
Let me know if I missed something / didn't understood
var index = 600_000 .. is same as .. var index : int = 600_000 int type is inferred and "high" returns highest value of int type, as expected.
if you need smaller range than int, well, use a range, like
type MyInt = range[0..1_000_000]
var last = index.high # expect to see 599_999,
Why would you expect that, and why would you apply high() on a int value? That never would come to my mind.
Nim has proc overloads, and proc can accept value or type parameters. High() for a seq makes sense of course. But applied on an int value, you expects that high() overload should give you the same as (val - 1)? I think returning the highest possible value makes more sense, but maybe high() should be not defined at all for int values, so that we would have to type high(typeof(myVal)).
Guys, I'm not seeking an advice how to program here, and I know how to read :) With all respect to you. This is why the topic in the design branch, not the question branch.
The compiler migh be not that smart, but people who design language are smart enough :) I assume that if I can use High on a value then I get the value - 1 and if I use High on a ordinal type I will get highest ordinal of this type. Simple as that.
I understand that this is working differently, but I can't say that I understand the logic behind how it works right now.
With all respect to you.
I gave a perfect answer, and I think I avoided all insulting words.
I assume that if I can use High on a value then I get the value - 1 and if I use High on a ordinal type I will get highest ordinal of this type. Simple as that.
Even if I try to think like you... Why ? If 600000 could get the value of 600000 why should high(600000) return 599999 ? It is already 600000, and 600000 is higher than 599999, right ?
Nim has type inference. So, its not that incomprehensible when you give it a value, nim infers it's type and high returns the "highest possible value" of that type. e.g Your index variable has the value of 600K but you can assign max_int to it on the next line of your program, could you not ? Thats what I understand from "highest possible value" and totally makes sense to me.
I understand your point of view and may agree, but I simply won't remember that high value of a variable will refer to a proc that will return high of an oridnal type. This is a operation where I need to remember some implicit rules and memory is a bad ally :)
I remember that "high is a nice feature that I didn't get in lang X, it allows me to take a index-1" straightforward. As I can use it everywhere I expect the same behavior.
It's just funny for me that I get in this situation several times already. Of course it's silly and is fixed right away.
I get what you're saying I think But think of it this way and see if you agree with me:
So there's the concept of (maximum value possible this thing can be), what should it return when asked of (foo:var int)?
I hope we agree it's INT_MAX,
What about var foo: range[0..9]? It should be 9
And when applied to array[0..9,int] ? Harder. I guess it could be [INT_MAX,INT_MAX... but that's not as useful as just giving us (maximum value possible that the index of this container could be)
So that's arguably a similar enough concept, it's certainly a useful quality, so rather than having two procs, let's say it returns range[0..9].high Ok, so then it should work the same with seqs and string.
Iunderstand where you come from, if you conceive of high as "seq.length minus 1" it's gonna get confusing,. cuz thats two jumps away from where it began, and the logic definitely doesn't work the other way. Does it make more sense to think of high as always operating on a type, but with a bit of an exception for arrays?
if you conceive of high as "seq.length minus 1" it's gonna get confusing
I believe seq is designed as (can be thought of) Nim's runtime resizable array anyway. So, It makes sense to me that high returns highest value for types and highest index for arrays (and containers).
I've learned Pascal before Python or Javascript etc. Maybe thats why almost all features of Nim makes sense to me without double checking.
I think we can change high for the better. :-)
high for integral types is fine but then high(3) should not compile as 3 is not a type, it's value. Likewise high for seq/arrays is ok and a different operation. In fact, it's a good example for how not to overload procs, 2 completely different operations under the same name. A PR that would deprecate the high(3) case would be acceptable, assuming that it doesn't break too much code out there.
It's just not intuitive :)
i dont understand how is value - 1 would be called high, we have pred for that.
i see zero problems with current behavior.
Indeed but then each container has it's own implementation since system.nim cannot know the internals.
So from there: https://github.com/nim-lang/Nim/blob/e08b802d/lib/system.nim#L291-L361, I suggest deprecating the first one:
proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect.}
## Returns the highest possible value of an ordinal value `x`.
##
## As a special semantic rule, `x` may also be a type identifier.
##
## See also:
## * `low(T) <#low,T>`_
##
## .. code-block:: Nim
## high(2) # => 9223372036854775807
proc high*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "High", noSideEffect.}
## Returns the highest possible value of an ordinal or enum type.
##
## ``high(int)`` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:.
##
## See also:
## * `low(typedesc) <#low,typedesc[T]>`_
##
## .. code-block:: Nim
## high(int) # => 9223372036854775807
proc high*[T](x: openArray[T]): int {.magic: "High", noSideEffect.}
## Returns the highest possible index of a sequence `x`.
##
## See also:
## * `low(openArray) <#low,openArray[T]>`_
##
## .. code-block:: Nim
## var s = @[1, 2, 3, 4, 5, 6, 7]
## high(s) # => 6
## for i in low(s)..high(s):
## echo s[i]
proc high*[I, T](x: array[I, T]): I {.magic: "High", noSideEffect.}
## Returns the highest possible index of an array `x`.
##
## See also:
## * `low(array) <#low,array[I,T]>`_
##
## .. code-block:: Nim
## var arr = [1, 2, 3, 4, 5, 6, 7]
## high(arr) # => 6
## for i in low(arr)..high(arr):
## echo arr[i]
proc high*[I, T](x: typedesc[array[I, T]]): I {.magic: "High", noSideEffect.}
## Returns the highest possible index of an array type.
##
## See also:
## * `low(typedesc[array]) <#low,typedesc[array[I,T]]>`_
##
## .. code-block:: Nim
## high(array[7, int]) # => 6
proc high*(x: cstring): int {.magic: "High", noSideEffect.}
## Returns the highest possible index of a compatible string `x`.
## This is sometimes an O(n) operation.
##
## See also:
## * `low(cstring) <#low,cstring>`_
proc high*(x: string): int {.magic: "High", noSideEffect.}
## Returns the highest possible index of a string `x`.
##
## See also:
## * `low(string) <#low,string>`_
##
## .. code-block:: Nim
## var str = "Hello world!"
## high(str) # => 11
I suggest deprecating the first one
That's what I tried to say, yes, completely agree.
A PR that would deprecate the high(3) case would be acceptable, assuming that it doesn't break too much code out there.
Deprecating shouldn't break anything, but let's see: https://github.com/nim-lang/Nim/pull/15283