Julia: scoped imports (feature request)

Created on 11 Oct 2019  路  9Comments  路  Source: JuliaLang/julia

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
feature modules

Most helpful comment

Changed the title since it seems like both import Foo and using Foo and all variations thereof ought to work in scoped contexts.

All 9 comments

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
Was this page helpful?
0 / 5 - 0 ratings

Related issues

JeffBezanson picture JeffBezanson  路  167Comments

shelakel picture shelakel  路  232Comments

jebej picture jebej  路  208Comments

StefanKarpinski picture StefanKarpinski  路  216Comments

kmsquire picture kmsquire  路  283Comments