Accessor for x->x[2]

Writing code like

sort(collect(dictionary), by = x->x[2])

frequently I miss CL:SECOND from Common Lisp. Were named accessors of this kind considered? Or is there a standard way to automagically make a closure of field names, eg something equivalent to

"Accessor function for a field name."
macro fa(fieldname)
    :(x->x.$fieldname)
end

sort(collect(dictionary), by = @fa second)

PS.: Of course I know that Dates has second and there would be a conflict.

first exists, but where do you stop?

Tradition guides our steps (10). :slight_smile:

1 Like

I dunno, @jeff.bezanson may have thoughts on this coming from Scheme instead of Common Lisp, but having a bunch of spelled out function names like seventh seems a lot less appealing to me than just writing x->x[7], which is only one more more letter anyway. If some proposal for terser lambdas were successful you could potentially express x->x[7] as something like _[7] or whatever. None of those proposals got any traction, however, because no one had a plausible answer for how to determine what the extent of the lambda body would be.

1 Like

Otherwise you could define (i::Int)(a::AbstractArray) = a[i] so your example becomes sort(collect(dictionary), by=2). This is what Clojure does. And I actually have defined a Field{name} type which when called on an object it gets the field of that name. So in this case I would write sort(collect(dictionary), by=field"second"). Or if I defined (s::Symbol)(o) = getfield(o,s) it could be slightly more concise but the Field{name} type is nice because it enables you to dispatch on the name of the field being accessed.

2 Likes

That’s pretty cool. Similar to how you can do with C arrays (c - With arrays, why is it the case that a[5] == 5[a]? - Stack Overflow)

I am against loading the language with named accessors. If I had to go with lambdas, I would prefer a proper macro:

# by number
macro by(n::Int) Expr(:kw, :by, :( x-> x[$n] )) end

sort(collect(dictionary), @by 2)

# by fieldname
macro by(sym::Symbol) Expr(:kw, :by, :( x-> getfield(x, $sym) )) end

second = :second # for some reason if passed directly it changes...
sort(collect(dictionary), @by second) # ...from Symbol to Expr
1 Like

@jkroso: can you please share how you define the function for Field{T}? I get

julia> abstract Field{T}
julia>  (::Field{T})(x) = getfield(x, T)
ERROR: UndefVarError: T not defined

I can do it with call, but that’s deprecated.

(::Type{Field{T}}){T}(x) = getfield(x, T)
2 Likes

I define it like this:

immutable Field{name} end
(f::Field{name}){name}(object::Any) = getfield(object, name)
macro field_str(s) Field{Symbol(s)}() end

Why not just use the last function?

As far as I understand, this thread is about cool code gymnastics, not really meant for actual usage in open source projects.