I really like the @something operation because it lets me write concise and readable code such as:
function get_operators(expr, operators=nothing)
return @something(operators, get_metadata(expr).operators)
end
This is shorter, and I find it more readable and even more robust since it includes additional assertions !== nothing which I wouldn’t normally write.
I was wondering if there’s something similar for field access. Throughout my library I often have code like this:
y = isnothing(x) ? nothing : x.val
# OR
y = isnothing(x) ? nothing : x[i]
Essentially, it tries to perform a getproperty/getindex operation, but propagates nothing if the object itself is nothing.
Before writing my own utility function, I just wanted to check: am I missing something already available in Base? It took me a few years to discover @something, so I wouldn’t be surprised if there’s another built-in shorthand I’m overlooking.
Hmm, maybe it’s a bit too magical but I almost wouldn’t mind it if single-arg @something f(x) worked as if !isnothing(x); f(x) end (where f may also be getfield, getindex, etc.)
It is a somewhat distinct idea, so maybe a new name like @maybe is worth it, but I’m really not sure why you’d ever use single-arg @something without it doing something like what I mention — at least I feel like it could be cool (worth mentioning at least).
Also, this is a code pattern I’ve run into a bunch myself, so FWIW it’s not just you getting fed up of manually writing !isnothing checks.
I guess I feel like @something should always return something that !== nothing, with the sole exception being if you wrap it with Some. So a single arg version feels a bit semantically uncomfy. Idk. Maybe even y = @safe x.val could be nice.
Oh yes, good point, I’m with you. Obviously it’s not an option here, but this kind of reminds me of syntax in other languages like thing?.property where nulls/errors are propagated before .property is hit.
Optics are already part of a lightweight, stable, and very popular Accessors.jl I like the Julian approach of very lightweight Base.
These “optional” optics (incl @maybe, @oget) can in general be upstreamed there from AccessorsExtra.jl, it just needs a more careful consideration of the api surface and edgecases. I never really came to do this.
Actually, maybe they shouldn’t be upstreamed to Accessors proper, but to a separate AccessorsMaybe package?.. The full AccessorsExtra.jl has a lot more stuff and I don’t focus on keeping it lightweight.
In my libraries, I try to minimise dependencies, particularly those that aren’t (yet) widely used. Small quality-of-life features (especially ones stable enough to rarely need updates) I tend to stick to only the ones from Base. Not only to reduce dependency management, but also as a type of language standardization, so that newcomers don’t have to learn different syntaxes for every utility library I am using. e.g., @something is in Julia itself so it isn’t too exotic for someone to encounter in my codebase.
However, if a dependency is well-contained and unambitious, I feel much more comfortable relying on it.
All of this is to say that, yes, I think AccessorsMaybe would be a great idea.
Light is generally pretty good, but in my mind at least I see just the basic but extensible interface as the sort of thing that could be pretty lightweight.
That said, these days package extensions are great for making it possible to have an optional implementation of an interface in a package.
I’d love to have this syntax supported in Base. We have the Union{T, Nothing} pattern all over the place and it’s well-established as a pattern in other languages. It would be super convenient to be able to do x?.y?.z?.a and have the nothings propagate.
Funnily enough, despite bringing up the ?. syntax, I’m actually not a fan of introducing it to Julia — I’m still pining for the ability to use ? in identifiers like ! (#22025).
There’s also the competing proposal to make T? sugar for Union{T, Missing} (#36628).
If we did have an error-value system like Zig/Rust I think having a dedicated syntax would be justified (this or some similar syntax), but I don’t think we’re quite there in Julia.
That said, I would very much like something to make this pattern easier, and this seems like something that could easily be accomplished with a macro. It occurs to me that the name @passnothing is pretty explicit, but maybe not terse enough to provide the sort of convenience that Jacob is looking for?