Julia: export keyword in front of functions / types

Created on 14 Aug 2014  Â·  34Comments  Â·  Source: JuliaLang/julia

This came up on the mailing list and having worked on Gtk.jl (see https://github.com/JuliaLang/Gtk.jl/blob/master/src/long_exports.jl) I think it would be a good thing to allow writing

export type MyType
    x::Int
end

export myfunc(m::MyType) = m.x

Don't know if it causes issues that export operates on methods rather than functions.

help wanted speculative

Most helpful comment

For what it's worth I'm not really in favor of this; it seems a little frivolous as surface syntax when a macro achieves the same thing with one extra character to be typed.

If people do really want the functionality, why not just add @export to the standard library rather than the parser? That should be strictly more conservative than adding it as actual language syntax.

(I also happen to like the up-front export list which has become the convention in package source and it can be a nice opportunity to group the package's public API in a meaningful way for people who will be working on the code.)

It's worth also considering Jeff's points here: https://github.com/JuliaLang/julia/pull/36474#issuecomment-651380656

One final point — I feel like exports are kind of a big deal and should deserve some careful thinking by package authors. So it might be ok to not have the utmost convenience in their syntax :-)

All 34 comments

It would also need to work with module variables. I like it.

I love this idea.

Just for completeness: The idea is taken from this thread https://groups.google.com/forum/#!topic/julia-dev/wi9YN-pcDR4 and most importantly it already has Jeffs blessing ;-)

I agree being able to write "export function foo(x) ... end" would be 
good. Having to write things in 2 places is always annoying. 

I guess if a function has multiple definitions it would still be exported if any of them had the export declaration?

Yes thats what i think as well. I just wanted to mention this slight method/function mismatch.

Or we can take the more restrictive approach and require all methods to be declared as exported. It is easier to loosen the requirement than to tighten it.

Should we allow a single module to use a mixed approach with both in line exports and top of file exports?

-1 one on this. If I want to see what methods are exported, I know exactly where to look. I don't want to be grepping through code to see what is exported where. I guess writing "things in 2 places is annoying", but placing everything at the top of a file is a good convention that favors reading code over writing code. I do much more of the former.

@jakebolewski: This is not about making the current way obsolete but to provide an alternative. So, if you favor the export list you can still use it.

This is a little like whether to write documentation in front of a function or in a separate document. People favor the one or the other. But I doubt one can make everybody happy when providing a single solution.

@ivarne: To your second point: I think we should make both possible. To your first point: I think this would lead to subtle bugs where one later adds a new function and forgets the export rendering all functions of the method private.

@tknopp It would have to be an error/warning, not a subtle bug.

I added "single" to emphasize what I'm talking about.

By error/warning you mean that the user is informed that only part of his functions have the export declarations right? Not sure if this enforcement is really required. For lazy people it might be a valid pattern to write a generic function including export (and @doc) and keep the specializations short without adding export in every case.

To the mixing within a "single" module. I don't know here either why enforcing one way within a module is required. Consistency is all fine but enforcing it is often a restriction. I have to cite Jeffs statement on the mailing list which made my day:

Yes modularity is good and important, but I also think junk food is ok once in a while.  

I felt this way, and in my own private code used to write

function somefunction(...)
    ....
end
export somefunction

function someotherfunction(...)
    ...
end
export someotherfunction

To be honest, I switched because, when I went back to code after a couple of months, I found it awkward to understand what I had intended as the "public" interface. Now I like having all the exports up top.

Related idea worth considering before doing anything like this is the ability to mark specific methods as public or otherwise default to non-public. See @simonster's comment here. I know we can use a different name for methods that aren't part of the API but it feels ugly.

@StefanKarpinski: But isn't this like if one would only have export working on a function basis instead of a method basis? So in theory, if we would remove the export list and use per function exports we would have everything we need right?

Indeed, but then export seems like a less appropriate name than public.

Whether to call this export or public is IMHO a different matter. Personally I think that public fits better because this is about visibility. But we should definitely not mix both terms.

Since I proposed this, I obviously like this idea. But I'm with Stefan that public is a more appropriate name. Also I'm not sure if it's a good idea if this were implemented to also keep the old way of export lists... Like it was mentioned this might lead to inconsistencies. Maybe in a transitional period we could keep both mechanisms but in the long run remove the export lists for more simplicity in the language?
I'm not of the school that there should be many ways to do the same thing. Sometimes choice is good but it can also lead to confusion,bugs,... Sometimes one way is simpler and better.

As far as the argument that with a keyword in front of the functions (& types & module vars) that this is distributed all over the place and hence not easy to see what is your public API: I find this a rather false argument: firstly: you can easily rearrange your module file to have all your public/exported functions in one section and the the others in another. That is effectively the same as having an export list as far as grouping is concerned. Secondly: once IDE will be more sofisticated they will take care of the grouping for you and will show the public functions together like you have in so many IDES like Eclipse, IDEA, Visual studio,...

The real motivation of this proposal is that is makes it almost impossible to forget to export your function/types/variables whereas it's very easy with an export list (which smells too much like C++ header files for my taste).

Just to chime in quickly, I think it's very important that we not assume that people will use IDE's. Any proposed change should constitute a Pareto improvement across both the IDE and non-IDE crowds.

Both the export list and the per function annotation have its pros and cons and I am not sure if it is realistic to reach consensus on one way at this point where people are used to the export list.

Actually having both would be quite consistent if we implement it the way Stefan proposes:

  • The export list would be used if want want to export all functions of a method
  • The function annotation would be used if one wants fine grained control or if one does not like the export list (e.g. because one has to lookup two place for function renaming)

@johnmyleswhite
Yes but my proposal isn't dependent on the use of an IDE . Even without an IDE you can group the public functions yourself which gives you the same ease of search as an export list.

@ssagaert, I kind of agree with that. I mostly think it's important to make sure that IDE's don't start to be part of the argumentation strategy used when debating changes to Julia.

I don't totally agree with your point, because having the public definitions grouped is much less concise than having the public names listed. For a package like DataFrames, you'd have to read a huge amount of code before you'd seen all of the public function definitions.

On 16 Aug 2014, at 19:03, John Myles White [email protected] wrote:

@ssagaert, I kind of agree with that. I mostly think it's important to make sure that IDE's don't start to be part of the argumentation strategy used when debating changes to Julia.

I don't totally agree with your point, because having the public definitions grouped is much less concise than having the public names listed. For a package like DataFrames, you'd have to read a huge amount of code before you'd seen all of the public function definitions.

—
Reply to this email directly or view it on GitHub.

yes it’s true that you’ll have to do page down more but you do not have to read all the code, just skim it for the function headers. But if your only objection is easily finding the public API, I feel this is actually an orthogonal issue: namely that of API documentation. If a tool would exist to automatically generated API doc (e.g. html) from source code that would divided the documentation in public API, private API & vars, then that would solve your problem and it could start from the function definitions annotated with “public" or “export".

Those are really good points. And I totally agree that, if 0.4 has a good documentation system, it would be much easier to discover the public API using the docs than by reading code. The current arguments seem very much conditioned on the current state of affairs, under which automatic doc generation doesn't occur.

I would agree that the reason I migrated away from that strategy is largely due to a lack of a decent documentation system. So I would drop what little remains of my objections if that other (more pressing) problem gets solved.

Solving this primarily through a doc system is a great idea.

I did express approval for this idea, but when reading over the Dates.jl change I found myself wanting to see a list of exports. Ultimately, having the list in one place seemed like a good thing. But if help was the standard way to get that, I think I would have been fine.

+1

When writing R packages, I find it quite cumbersome to maintain a list of exported functions separately from the method definitions themselves.

Is this something that might be implemented in the 0.4 dev period? There was not fully agreement but various people liking it.

+1 to this idea. This would make it closer to ES6 modules (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) and it would reduce the number of lines avoiding noise in my opinion.

Regarding the utility of having a single place to look upon the exposed functions, I think this is useful when the exported functions are the API of a library, but I think that for application code the proposal is more convenient.

I love this idea too.

Is it possible to export only the specific functions that are marked export, taking into account the complete signature? That would solve the include/exclude-all issue above.

All that's required to make this happen is someone hacking the parser to make it work.

If anyone is interested, I made a small package that provides an @export macro here: https://github.com/dalum/InlineExports.jl

For what it's worth I'm not really in favor of this; it seems a little frivolous as surface syntax when a macro achieves the same thing with one extra character to be typed.

If people do really want the functionality, why not just add @export to the standard library rather than the parser? That should be strictly more conservative than adding it as actual language syntax.

(I also happen to like the up-front export list which has become the convention in package source and it can be a nice opportunity to group the package's public API in a meaningful way for people who will be working on the code.)

It's worth also considering Jeff's points here: https://github.com/JuliaLang/julia/pull/36474#issuecomment-651380656

One final point — I feel like exports are kind of a big deal and should deserve some careful thinking by package authors. So it might be ok to not have the utmost convenience in their syntax :-)

I don't buy that argument. If export is a special keyword, it is an additional thing to remember whether an @ in-front of it and sometimes not. I favor consistency here.

True, but one doesn't _need_ the ability to export functions by doing export function instead of separately. If that was clearly a desirable feature, then sure, we should do this instead of InlineExports but I think the deeper question is whether it's desirable or not in the first place.

yep, that was kind of my point. Either this is a feature we want, then please let's use consistent naming. Or don't implement it at all.

Nowadays I am not so certain anymore. When reorganizing code and removing functions it happens regularly that I miss also to remove the export. But on the other hand this feature is not so important to be personally that I would dependent on another package just to have it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

TotalVerb picture TotalVerb  Â·  3Comments

sbromberger picture sbromberger  Â·  3Comments

ararslan picture ararslan  Â·  3Comments

wilburtownsend picture wilburtownsend  Â·  3Comments

i-apellaniz picture i-apellaniz  Â·  3Comments