getindex for a real number

325 views
Skip to first unread message

Ehsan Eftekhari

unread,
Nov 30, 2015, 3:32:46 AM11/30/15
to julia-users
 I have a question about this behaviour of getindex in Julia:

if I say

julia> a=1.0
1.0

then

julia> a[1]
1.0

julia> a[end]
1.0

but

julia> a[:]
ERROR: MethodError: `getindex` has no method matching getindex(::Float64, ::Colon)
Closest candidates are:
  getindex(::Number)
  getindex(::Number, ::Integer)
  getindex(::Number, ::Integer...)
  ...

Why the last one does not work?

Mauro

unread,
Nov 30, 2015, 4:01:54 AM11/30/15
to julia...@googlegroups.com
As it says, there is no method for it. You could add it yourself:

Base.getindex(f::Float64, ::Colon) = f # or whatever you like

However, the philosophical question is: should you be allowed to index
into a float (or int)? Julia usually puts convenience before strictness
and allows this. I'm not sure there are technical reasons to draw the
line at `1[:]`. If no-one gives one, you could open a pull request
(probably should add a method for `q[1:end]` too).

Ehsan Eftekhari

unread,
Nov 30, 2015, 4:25:32 PM11/30/15
to julia-users
Thanks Mauro. As you predicted, my question was about the reasoning behind this behavior. If I remember correctly, it was not possible to use getindex on real numbers in Julia 0.3. I was not sure why it is added to 0.4.

Mauro

unread,
Nov 30, 2015, 4:47:39 PM11/30/15
to julia...@googlegroups.com
Your welcome. Your recollection is wrong though, this was possible in
0.2 and 0.3; I just checked (I don't have a 0.1 build but maybe I
should...).

On Mon, 2015-11-30 at 22:25, Ehsan Eftekhari <e.eft...@gmail.com> wrote:
> Thanks Mauro. As you predicted, my question was about the reasoning behind
> this behavior. If I remember correctly, it was not possible to use getindex
> on real numbers in Julia 0.3. I was not sure why it is added to 0.4.
>
> On Monday, November 30, 2015 at 10:01:54 AM UTC+1, Mauro wrote:
>>
>> As it says, there is no method for it. You could add it yourself:
>>
>> Base.getindex(f::Float64, ::Colon) = f # or whatever you like
>>
>> However, the philosophical question is: should you be allowed to index
>> into a float (or int)? Julia usually puts convenience before strictness
>> and allows this. I'm not sure there are technical reasons to draw the
>> line at `1[:]`. If no-one gives one, you could open a pull request
>> (probably should add a method for `q[1:end]` too).
>>
>> On Mon, 2015-11-30 at 09:32, Ehsan Eftekhari <e.eft...@gmail.com

Ehsan Eftekhari

unread,
Dec 1, 2015, 12:55:03 PM12/1/15
to julia-users
Then I remember sth else. Most probably I have tried ones(size(a)) in Julia when `a` is a real number, and it does not do what the same command does in Matlab.
There are some other indexing that work in Julia, e.g.,
a=1.0
a[1]
a[1,1]
a[1,1,1,1]
a[end,end,end]
all return 1.0. But if I say size(a) it returns ().
Or if I say b=ones(1,1,1)
then again b[1,1,1,1,1] or b[1,1,:,1] return 1.0, but b[1,1,1,:] throws an error.

Eric Forgy

unread,
Dec 1, 2015, 6:19:34 PM12/1/15
to julia-users
A scalar is distinct from a vector so size(a) = () makes sense. getindex for a scalar does not make sense and should probably be removed on the grounds of mathematical elegance :) Any code that depends on referencing a scalar via an index is probably flawed in the first place.

Tim Holy

unread,
Dec 1, 2015, 8:38:50 PM12/1/15
to julia...@googlegroups.com
Conversely, there are many people who seem to want Julia to treat scalars and
1-vectors indistinguishably (ala Matlab).

For what it's worth, here's a (contrived) example to justify the current
behavior:

function sum_over_dims(A, dims)
for d in dims
A = sum(A, d)
end
A
end

sum_over_dims(A, [2,3])
sum_over_dims(A, 2)

Why should I write sum_over_dims(A, [2]) in the latter case?

Best,
--Tim

Eric Forgy

unread,
Dec 1, 2015, 9:38:46 PM12/1/15
to julia-users
It bugs me, but only a little, so I won't lose sleep over it :)

Then again, I wish Julia had a "strict" mode. In strict mode, the language would be more pure mathematically, e.g. scalars have no indices, the transpose of a vector is a covector, etc. This bit me recently because if T <: U, then Array{T} is NOT <: Array{U} although as, sub-modules, Tmodule <: Umodule.

Then again, as I'm learning, if we want Julia to do something bad enough, e.g. have a "strict" mode,  we can have it. For example, I could write a package "strict.jl" where 

using strict

would kill Base.getindex(::Number) and things like that. That could be cool :)

Tim Holy

unread,
Dec 1, 2015, 10:02:45 PM12/1/15
to julia...@googlegroups.com
Likewise, I do see why this is a little troublesome. It's annoying when you
mean to write `for i = 1:n` but accidentally write `for i = n`; it's not
always an easy bug to find.

--Tim

On Tuesday, December 01, 2015 06:38:46 PM Eric Forgy wrote:
> It bugs me, but only a little, so I won't lose sleep over it :)
>
> Then again, I wish Julia had a "strict" mode. In strict mode, the language
> would be more pure mathematically, e.g. scalars have no indices, the
> transpose of a vector is a covector, etc. This bit me recently because if T
> <: U, then Array{T} is NOT <: Array{U} although as, sub-modules
> <https://en.wikipedia.org/wiki/Module_(mathematics)>, Tmodule <: Umodule.

Eric Forgy

unread,
Dec 1, 2015, 11:05:07 PM12/1/15
to julia-users
It's a start :)



julia> using strict

julia
> a = 5
5

julia
> a[1]
ERROR
: MethodError: `getindex` has no method matching getindex(::Type{Number}, ::Type{Integer})
Closest candidates are:
  getindex
(::Type{T}, ::Any...)
  getindex
{T<:Union{Char,Number}}(::Type{T<:Union{Char,Number}}, ::Range{T})
  getindex
{T<:Union{Char,Number}}(::Type{T<:Union{Char,Number}}, ::Range{T}, ::Range{T}...)
 
in getindex at C:\Users\Eric Forgy\.julia\v0.4\strict\src\strict.jl:4

Eric Forgy

unread,
Dec 2, 2015, 4:49:22 AM12/2/15
to julia-users
Some more improvements...

julia> n = 5
5

julia
> for i = n
       println
(i)
       
end
5

julia
> using strict

julia
> for i = n
       println
(i)
       
end
ERROR
: MethodError: `start` has no method matching start(::Type{Number})
 
in start at C:\Users\Eric Forgy\.julia\v0.4\strict\src\strict.jl:24

Tim Holy

unread,
Dec 2, 2015, 7:15:14 AM12/2/15
to julia...@googlegroups.com
Seems like this has the makings of a nice package for debugging.

Best,
--Tim

Seth

unread,
Dec 2, 2015, 8:11:32 AM12/2/15
to julia-users
This is great. I assume it catches "for i in n" where n is a scalar, also, right?

I could see requiring this by default in all my packages.

Steven G. Johnson

unread,
Dec 2, 2015, 8:47:44 AM12/2/15
to julia-users
On Tuesday, December 1, 2015 at 9:38:46 PM UTC-5, Eric Forgy wrote:
Then again, I wish Julia had a "strict" mode. In strict mode, the language would be more pure mathematically, e.g. scalars have no indices, the transpose of a vector is a covector, etc.

Not all vectors represent elements of a Hilbert space, and not all 2d arrays represent linear operators.  Sometimes arrays are just containers, for which those algebraic operations aren't sensible.  There's nothing "impure" mathematically about this, any more than there is something "impure" about a broadcasting operation like .* ... mathematics encompasses more than linear algebra.

The reason that scalars are iterable is that it can make it easier to write generic code, where the same code works if the argument is a single number or a container of numbers.  The question is not whether this is a valid operation in linear algebra, but rather whether the convenience of being able to treat numbers as indexable length-1 containers outweighs the potential for confusion.  Reasonable people can disagree about this, but let's please not get into metaphysical debates about purity.

Glen O

unread,
Dec 2, 2015, 9:17:07 AM12/2/15
to julia-users
On Wednesday, 2 December 2015 11:38:50 UTC+10, Tim Holy wrote:
Conversely, there are many people who seem to want Julia to treat scalars and
1-vectors indistinguishably (ala Matlab).
Sure, but it should be one way or the other, not half way between. In Matlab, scalars are literally 1-vectors, so everything that works with 1-vectors works with scalars. In Julia, some things work, and others don't. That just results in confusion.

As an example, reshape(1,1) throws an error, and squeeze(1,(1,)) gets stuck in an infinite loop. vec(1) throws an error, as does cumsum(1). And of course there's the issue with getindex involving colon, arrays or ranges for indexing (you'd think that, just as a[[1,1]] gives the value of a[1] twice for an array, that it would do the same for a scalar, but it doesn't).

I can understand the desire not to have them be identical (since there are cases where a function should do a different thing for a number than it does for an array), yet allow partial compatibility... it's just a little arbitrary which cases work and which don't. 

Tim Holy

unread,
Dec 2, 2015, 9:20:39 AM12/2/15
to julia...@googlegroups.com
On Wednesday, December 02, 2015 05:11:32 AM Seth wrote:
> This is great. I assume it catches "for i in n" where n is a scalar, also,
> right?
>
> I could see requiring this by default in all my packages.

Might be better as a test dependency, since it works by "breaking" methods in
Base. If you include it in your package by default, you risk fragmenting Julia
into incompatible dialects.

--Tim

Tim Holy

unread,
Dec 2, 2015, 12:21:34 PM12/2/15
to julia...@googlegroups.com
Glen, that's a great list of bugs. Have you considered filing them as issue(s)?

Some immediate thoughts:

On Wednesday, December 02, 2015 06:17:06 AM Glen O wrote:
> As an example, reshape(1,1) throws an error

I'm not sure that's a real problem, although indeed implementing reshape on
numbers would be more efficient than reshape([1], (1,1,1)) because in the latter
you're creating two arrays. So possibly this is something we should implement.

> , and squeeze(1,(1,)) gets stuck
> in an infinite loop.

That's definitely a bug. It's surely a very slow stack overflow (infinite
recursion).

> vec(1)

Similar to reshape...maybe/maybe not.

> throws an error, as does cumsum(1).

Since sum(1) works, this should too. Bug.

> And of
> course there's the issue with getindex involving colon, arrays or ranges
> for indexing (you'd think that, just as a[[1,1]] gives the value of a[1]
> twice for an array, that it would do the same for a scalar, but it doesn't).

Bug

> I can understand the desire not to have them be identical (since there are
> cases where a function should do a different thing for a number than it
> does for an array), yet allow partial compatibility... it's just a little
> arbitrary which cases work and which don't.

Reports would help---not everyone hits these (I'm not sure I ever have).

Cedric St-Jean

unread,
Dec 2, 2015, 12:51:35 PM12/2/15
to julia-users
There's also

x = [1 2; 3 4]
x
[:,[1]] # returns 2D array
x
[:, 1] # returns 1D array
x
[1, :] # AFAIK, returns 2D under Julia 0.4 and 1D under 0.5

I like the 0.5 behaviour a lot better.

Ehsan Eftekhari

unread,
Dec 3, 2015, 5:03:24 PM12/3/15
to julia-users
Sure, but it should be one way or the other, not half way between.
+100
Reply all
Reply to author
Forward
0 new messages