Julians seem to dislike qualified names and therefore like using unqualified using
. I hate that. An interesting compromise is the open
keyword in OCaml.
(* making names in Printf globally available *)
open Printf;;
let add_one_to_all list =
(* names in `List` (like `map`) only available in subexpressions *)
let open List in
map ((+) 1) list
I was thinking a scoped version of using
might be interesting for similar functionality; to bring unqualified names into the current scope without contaminating the entire module.
function drop5(iter)
# names in `Iterators` only available in the function scope.
using Base.Iterators
drop(iter, 5)
end
This would be really nice, I've wanted it on several occasions.
Changed the title since it seems like both import Foo
and using Foo
and all variations thereof ought to work in scoped contexts.
Thinking more about the semantics of this, it would be _really_ cool if methods added to external functions would only be active in the scope (e.g. methods on operators in Base
), but I imagine that would be a bit tricker (or impossible-er) than just confining the names to a certain scope.
That's a very different kind of feature.
It might theoretically be possible if something like an immutable binary tree was used to implement the set arithmetic for the type hierarchy so sets of types and methods could be extended within certain scopes without rewriting the hierarchy globally. Could also potentially have a positive effect on the situation where Base, Core and Core.Compiler end up including the same code over and over again and might speed up method resolution in some cases because a smaller set of types and methods would be in play in any given scope. Of course, I'm sure there would be trade-offs.
But yeah, that's kind of a fundamental rewrite of the compiler, not just a namespace trick. It was just an idea that popped into my head, but it probably makes more sense as part of an entirely different discussion.
The issue is that that is a massive semantic change because it changes which methods are visible. So yes, very different discussion. I know @TsurHerman has had some ideas similar to this, sometimes called "context dispatch": https://discourse.julialang.org/t/multifunctions-context-dispatch-and-binary-cache/11565
Also note that if you want a lexically scoped method extension, it's very easy:
+(args...) = Base.:+(args...)
+(ss::AbstractString...) = string(ss...)
# In this module `+` does string cat
I'm not aware of people wanting something like that too often though.
Also note that if you want a lexically scoped method extension, it's very easy:
+(args...) = Base.:+(args...) +(ss::AbstractString...) = string(ss...) # In this module `+` does string cat
I'm not aware of people wanting something like that too often though.
I love this. 馃槏
I'm not aware of people wanting something like that too often though.
A somewhat useful example may be to change the associativity of *
(https://discourse.julialang.org/t/why-is-multiplication-a-b-c-left-associative-foldl-not-right-associative-foldr/17552):
let *
*(args...) = foldr(*, args)
A * B * C * D * x # matrices * vector
end
However, lexical nature can be a bit "surprising"
let *
*(args...) = Base.:*(args...)
*(x::String, y::String) = "($x * $y)"
@show "a" * "b" # works
@show ("a" * "b") * "c" # works
@show "a" * "b" * "c" # don't work
end
Of course, you need to do
let *
*(args...) = foldl(*, args)
*(x, y) = Base.:*(x, y)
*(x::String, y::String) = "($x * $y)"
...
end
instead.
function drop5(iter) # names in `Iterators` only available in the function scope. using Base.Iterators drop(iter, 5) end
I often use "using M: x
" which we already have:
using Parameters: @unpack
function drop5(iter)
@unpack drop = Base.Iterators
drop(iter, 5)
end
Most helpful comment
Changed the title since it seems like both
import Foo
andusing Foo
and all variations thereof ought to work in scoped contexts.