JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.71k stars 5.48k forks source link

Should the returned value of a public function applied to public types be public #55280

Open LilithHafner opened 3 months ago

LilithHafner commented 3 months ago

Should the returned value of a public function applied to public types be public? I think yes, but want to hear other folks' opinions before making PRs.

Adapted from @jariji's post in https://github.com/JuliaLang/julia/issues/52725#issuecomment-2254248688

nsajko commented 3 months ago

Not necessarily. I know some disagree, but I'm not sure why. Sometimes it makes sense to return an opaque value, meant to be passed to other parts of the API of the same package.

adienes commented 3 months ago

I agree with @nsajko here. Consider the pattern

struct Foo
    # never construct directly! always use external constructors!
end

function fooconstructor(...) # returns a `Foo`
    ...
end

and fooconstructor is made public. If this means Foo must also be public, then either

as an example maybe particularly common in the Julia ecosystem, I'm imagining

function hybrid_algorithm_smart_solver(input)
    algo_1_best(input) && return _internal_alg_1(input)
    algo_2_best(input) && return _internal_alg_2(input)
    ...
end

### as a user

using SolverKit: hybrid_algorithm_smart_solver, solve!

alg = hybrid_algorithm_smart_solver(input)
params = solve!(alg)

### params are of some public type. but `alg` is not necessarily, except that I can pass it to `solve!`
LilithHafner commented 3 months ago

It's possible to have no outer constructors

struct Internal
    x::Int
    global _Internal
    _Internal(x) = new(x)
end

make_a_thing(x::Int) = _Internal(x)
jariji commented 3 months ago
alg = hybrid_algorithm_smart_solver(input)
params = solve!(alg)

is a good example.

its outer constructor methods are not public (bad, because what does it mean for Foo to be public if its methods are not)

I think we can say this is fine: the type is public, its constructor isn't public but its solve! method is public.

As a user I don't like to have any objects in my workspace that are undocumented or nonpublic.

nsajko commented 3 months ago

the type is public, its constructor isn't public

It doesn't work like that. A name is either public or it's not.

jariji commented 3 months ago

The name is public, but the documentation says its public API is only solve!(x::Foo).

nsajko commented 3 months ago

The name is public, but the documentation says its public API is only [...]

IMO that's too much to ask of package authors.

vtjnash commented 3 months ago

With getfield, a Module, and a Symbol (all public objects), the program could get to anything as a return value, so it is not trivially the case that anything accessed via public functions is public. Perhaps though that anything returned is likely allowed as being public as an argument, but not as the function argument?

tecosaur commented 3 months ago

Hmm, rolling this over in my mind isn't this a rather fundamental consequence of choosing to make publicity be with respect too names rather than methods?

jakobjpeters commented 2 months ago

If not public, it would be nice to always have a docstring that tells you what you can do with it.