Julia: Only make exported bindings available with `import`

Created on 8 Jul 2015  路  12Comments  路  Source: JuliaLang/julia

My (maybe wrong) understanding is that the public API of a package is what its main module exports.

However, exports only impact when using a Package and not when importing. However, for larger scale software projects it is probably often preferable to use import to get the safety benefits of separate name-spaces. But this means that when I program in the "safer" import-mode there is no easy way to tell whether I use the public API or some private feature. So, it's not really safer at all.

I wonder whether it would make sense and be more consistent with using that import only allows access to the exported bindings, and that importall imports all the bindings (and also allows method extension, i.e. as it is now):

module A
export a
a() = 1
b() = 2
end
# Defining a module in-line does an implicit
#import A

# now only exported symbols are available
A.a() # works
A.b() # ERROR: UndefVarError: A.b not defined

importall A
A.b() # now works
A.a(x) = 5 # can now be extended
A.b(x) = 5 # can also be extended

(this needs more working out though)

This would be a breaking change but could maybe be done through depreciation warnings. Worth the hassle though?

Or could/should one write a @safeimport macro doing above?

Related: #8000.

modules

Most helpful comment

In case it helps.... the following Discourse comment provides and example of how to create private properties for a type.

All 12 comments

there seems to be a mixing of terms here. importall is explicitly doing the import of absolutely everything. it's target usage is really interactive development, where you don't really care about safety or conventions, but just want to try out an idea quickly. using makes the exports available. import is the safe option for listing exactly what you want.

No, I'm arguing that there should be a construct which only makes the exported variables available through the fully qualified dot-syntax. Reiterating above example, package A defined like so:

module A
export a
a() = 1
b() = 2
end

now using this with, let's call it import_only_exported for the sake of clarity:

import_only_exported A

# now only exported symbols are available with fully qualified syntax
A.a() # works
A.b() # ERROR: UndefVarError: A.b not defined

# none are introduced to the current workspace:
a() # ERROR: UndefVarError: a not defined
b() # ERROR: UndefVarError: b not defined

But it was maybe a bit confusing as I suggested both import and importall be modified slightly (in an effort to keep the number of keywords constant...).

The idea would be that import_only_exported would allow to easily program with only the public API (i.e. what's exported) without having to pollute your name-space with using. I don't think that is possible at the moment but it may be of value?

If field overloading was allowed and .. became the operator for direct field access (https://github.com/JuliaLang/julia/issues/1974), then I'd be in favor of making unexported functions available only using A..b().

But adding yet another variant of import would only create more confusion IMHO.

The problem exists also when you are doing specific imports, eg

import A.b

works even though b is not exported in A.

I agree that it should be possible to import things in a way that protects you from importing an unexported symbol by mistake, also when using the more disciplined alternatives to using. This is no simple fix though, and I'm not sure what could be a good solution.

Restricting access to A.b seems to require some kind of access restriction as discussed in #12064, but coming up with a form of import that disallows to import A.b seems more about coming up with the right syntax (which is hard enough, of course :)

I like @nalimilan's suggestion, if the .. comes along.

Would it be possible to chain the private symbols. I.e. that in the initial example b would only be accessible by A.A.b() ? I know that this might currently be a technical problem (since A == A.A) but conceptually this could work

As an alternative to .., which other people have expressed a desire to use for intervals, IIRC, what about .!. I think it is less accident prone (one vs two dots is harder to see), and more visible (exclamation points do grab your attention).?

I definitely want a way to be able to access the exported members – and only the exported members – using the module name as a namespace qualifier. This is to avoid PHP's massive global namespace, which leads to confusion as to what name comes from what module.

Ping?

This seems like a major problem for large-scale projects. Common Lisp solved it by separating a:b (accesses only exported symbols in package a) and a::b (accesses any symbol in package a).

Can I ask what is the status of this proposal?
Is it placed in the roadmap (and in what shape?), rejected or still under discussion?

In case it helps.... the following Discourse comment provides and example of how to create private properties for a type.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iamed2 picture iamed2  路  3Comments

i-apellaniz picture i-apellaniz  路  3Comments

ararslan picture ararslan  路  3Comments

arshpreetsingh picture arshpreetsingh  路  3Comments

wilburtownsend picture wilburtownsend  路  3Comments