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

Inconsistency in constructing Dict and Array #3214

Closed
ingmarschuster opened this issue May 27, 2013 · 17 comments
Closed

Inconsistency in constructing Dict and Array #3214

ingmarschuster opened this issue May 27, 2013 · 17 comments
Labels
needs decision A decision on this change is needed
Milestone

Comments

@ingmarschuster
Copy link

Both Dict and Array are parametric types. Constructing a Dict and an Array of variable size differs markedly, though:
* Dict{TypeA,TypeB}()
* Array(Type) while Array{Type}() doesn't work
This creates some confusion for people new to the language – also I think its inconsistent design.

@diegozea
Copy link
Contributor

Related to #2067

@amitmurthy
Copy link
Contributor

Some other confusing (to me at least) behaviors:

julia> Int32[]
0-element Int32 Array

julia> NTuple[]
0-element NTuple{N,T} Array

julia> Tuple[]
ERROR: no method getindex((DataType,),)

and

julia> Array(Int32, 0)
0-element Int32 Array

julia> Vector(Int32)
ERROR: type: apply: expected Function, got Type{Array{T,1}}

@JeffBezanson
Copy link
Sponsor Member

Array{Type} is actually a partially-instantiated type (there is a second parameter for the number of dimensions), which currently means it can't have a constructor.

The T[] syntax did not always exist, and unfortunately tuple types are both types and indexable. But, you can't index a tuple with a tuple, so we could potentially define Tuple[Tuple...], distinct from Tuple[Int].

@ingmarschuster
Copy link
Author

I can see why you might want to go wait until you can have constructors for partially-instantiated types; but maybe explicit is better than implicit here? Dynamically growing Arrays (Vectors in C++ lingo) are implemented really different from fixed-size Arrays (I didn't look at julias implementation but I guess it uses the conventional size & capacity book keeping?). Giving them a different name would make that very transparent, while functions can still be developed against a common abstract supertype.

@JeffBezanson
Copy link
Sponsor Member

There would be some advantages to having growable vectors separate from non-growable multi-dimensional arrays. But you would still be left without the syntax Array{T}(m,n) for constructing 2d arrays.

@ingmarschuster
Copy link
Author

I think not having the syntax Array{T}(m,n) becomes a non-issue as soon as people perceive Arrays as being fixed size. Also Arrays will be used very rarely and only when people are pretty sure it wont grow in size - see Go arrays vs. slices ("Arrays have their place, but they're a bit inflexible, so you don't see them too often in Go code. Slices [Vectors in C++ lingo], though, are everywhere.", http://blog.golang.org/2011/01/go-slices-usage-and-internals.html)

@quinnj
Copy link
Member

quinnj commented Aug 29, 2014

This should be affected by plans in #1470.

@JeffBezanson
Copy link
Sponsor Member

We have an update here! It is now possible to define constructors for Array{T} and Array{T,N}. They can also call convert, so for example we currently have

julia> Array{Int}([1.0,2.0])
2-element Array{Int64,1}:
 1
 2

I think it would be better to use Array{Int}(m,n) instead of Array(Int, m, n), but it does conflict slightly with the convert use above. Any suggestions on how to resolve this welcome.

@kmsquire
Copy link
Member

Nice! How does it conflict? In Array{Int}(m,n), m and n are presumably numbers, and in Array{Int}([1.0,2.0]), the only argument is an Array, right? What am I missing?

@JeffBezanson
Copy link
Sponsor Member

It's only a slight conflict. The problems would start if we wanted to be able to convert a number to a 1-element array. It wouldn't be clear what Array{Int}(2) did.

@kmsquire
Copy link
Member

I see. I don't think there's a problem with numerical constants (just pick a behavior), but I can see an issue in code where, e.g., a could be a number or an array, and we want

Array{Int}(a)

to be consistent.

@StefanKarpinski
Copy link
Sponsor Member

Numbers pretending to be containers strikes again.

@jakebolewski
Copy link
Member

Could that behavior go away in 0.4?

@JeffBezanson
Copy link
Sponsor Member

I don't really think numbers pretend to be containers. If we had a Container type, Number would not be a subtype of it. They just implement a couple things like iteration. There are also various ways to implement Array{T}(...) to avoid this problem, such as what we have now where passing a number is an error.

@jakebolewski
Copy link
Member

They support size, ndims, length , getindex, first, last, and isempty along with iteration. This seems to be pretty comprehensive in supporting the Container interface, what is missing?

@JeffBezanson
Copy link
Sponsor Member

There are functions that don't treat numbers like containers, e.g.

julia> a
0-dimensional Array{Int64,0}:
1

julia> b = rand(2,2)
2x2 Array{Float64,2}:
 0.292566  0.671567
 0.774752  0.983408

julia> a + b
ERROR: dimensions must match
 in promote_shape at operators.jl:215
 in promote_shape at operators.jl:206
 in + at array.jl:716

julia> b + ones(1,)
ERROR: dimensions must match
 in promote_shape at operators.jl:190

julia> b + 1
2x2 Array{Float64,2}:
 1.29257  1.67157
 1.77475  1.98341

@nalimilan
Copy link
Member

Anyway it doesn't make much sense to try converting a Number to an Array, so assuming a single Number represents the size of the first dimension sounds fine. As regards tuples (cf. #9370 (comment)), we can require splatting, so that you'd need to write Array{Int}((2, 2, 2)...)) if (2, 2, 2) is the size of the new array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs decision A decision on this change is needed
Projects
None yet
Development

No branches or pull requests

9 participants