Inconsistency of type argument positions

question

#1

I happened to met the depwarn

readstring(x) is deprecated to read(x, String)

And noticed some inconsistency. Note the following functions:

julia> parse(Int, "1234")
  1234

julia> floor(Int, 1.2)
  1

So, is read(String, io) make any sense?


edit: here’s what I found from the julia repo itself,

List1:

  • zeros(Int, N)
  • getindex(Int8, 1, 2, 3)
  • ceil(Int,N/2)
  • reinterpret(Int, ccall(:jl_eqtable_nextind, Csize_t, (Any, Csize_t), a, i))
  • map(Int,dims)
  • bitcast(Int, x)
  • convert(Int, sz)
  • tryparse(Int, env_str)
  • trunc(Int,x)
  • round(Int, 1.7)
  • floor(Int, log10(abs(x)))
  • parse(Int, "1234")
  • rationalize(Int, x; kvs...)
  • unsafe_trunc(Int,n)
  • tryparse(Int, env_cores)
  • tryparse_internal(Int, sbuff, startpos, endpos, 0, false)
  • ones(Int, 4, 4)
  • typeparam(Int, rand(Int, 2))
  • transcode(String, val)
  • LibGit2.get(String, cfg, "branch.$branchname.remote")
  • collect(Float64, 1:2:5)
  • ounding.setrounding_raw(Float64, Rounding.JL_FE_TONEAREST)
  • splitprec(Float64, i)
  • Base.unsafe_convert(Int32, Base.cconvert(Int32, x))
  • SparseArray(Float64, 3, 3)
  • Base.sitofp(Float64, %9)
  • rand(Float64,10,10)
  • hilb(Float64,n)
  • onediag(Float64, m, n)
  • tridiag(Float64, m, n)
  • sprand(Float64, 3, 0.75)
  • spzeros(Float64, 3, 3)
  • Base.typed_hcat(Float64, B, B, B)

List 2:

  • empty([1.0, 2.0, 3.0], String)
  • read(`$shell -c "printf %s $(shell_escape_posixly(dir))"`, String)
  • isa(s[2], String)
  • similar(s, Int)
  • rand(m, Int)
  • π (%1, Float64)

#2

There’s been some discussion about this. The problem is that we have conflicting rules in this case, since we also usually put I/O streams as first arguments so that the do syntax works (see e.g. open) (EDIT: this is wrong, see below). IIRC it’s been decided that I/O streams take priority over return type parameters for that reason.


#3

Okay, thanks for the info~


#4

How about support these two forms simultaneously?


#5

I thought it was functions that took precedence as the first argument because of the do syntax (open returns an I/O stream, but the body of the do becomes an anonymous function with is the first argument to open), not I/O streams.


#6

I’ve done that, in the Strs.jl package, where I wanted to support the do syntax, but the first argument was otherwise a Type, allow the function first or the type.

Scott


#7

Woops, yes, actually I confused read with open. We don’t actually care about passing the I/O stream as the first argument, that’s only useful for functions. So whether to pass the I/O stream or the type as first argument is mostly arbitrary.


#9

Does it make sense to open an issue/pr on this? As in the first post, almost no function put type argument on non-first position


#10

In this case, I think the more important factor is that the first argument (I/O stream or filename) is always needed, but the type to read it into is optional.
I wouldn’t like to have to put String in 99% of the time, just to be consistent with the “rule” that the type should go first.


#11

It is optional no matter at first or second position. Just like floor


#12

But no function puts the I/O stream in non-first position either. You can’t satisfy both conventions at the same time.


#13

fine :man_shrugging:


#14

The order is given in https://github.com/JuliaLang/julia/issues/19150#issuecomment-320811138

(idk if this is in the docs somewhere as well, it should be, if not that is an issue to open.)

Important part is: Jeff’s comment:

I propose the following priority order (highest priority listed first):

  1. Function argument (for HOFs accepting one function, or for use with do blocks)
  2. IO stream
  3. Thing being mutated (Edit: to hold the main result of the computation)
  4. Type
  5. Collection (not being mutated)
  6. Key
  7. Value
  8. Everything else

Exception: first argument to convert is always the type.


#15

I wonder why Jeff considered convert an exception?
Type is #4, and Value is #7, so that follows Jeff’s list.
I’m not aware of any convert methods that allow 1,2, or 3.

For convert, the ordering also makes a lot of sense given the similarity to constructors and the order that assignment works: dest = source, so DestType(source) or convert(DestType, source) all scan well.