I think it's reasonable to adopt a convention in some code of not using `using`.

Another way to look at this is that a library author could affect name
visibility in somebody else's code by adjusting the signature of a
method. That doesn't seem like a desirable interaction to me. Often
somebody might initially define foo(::Image), and then later realize
it's actually applicable to any array, and change it to
foo(::AbstractArray). Doing that shouldn't cause any major fuss.

On Wed, Apr 22, 2015 at 5:58 PM, Michael Francis <[email protected]> wrote:
> You are correct it is restrictive, though I will take some convincing that
> this is a bad thing, as systems get larger in Julia it is going to be
> increasingly important to manage code reuse and prevent accidental masking
> of types. Multiple dispatch is a wonderful tool for supporting these goals.
> Unfortunately allowing people the ability to export get(<string>) et al to
> the users scope seems like a bad idea. This is already happening from
> modules today. Perhaps the middle ground is to force an explicit import, so
> using only imports functions which have types defined in the module.  The
> person defining the module exports all the functions they want but only
> those that are 'safe' e.g. follow my original rule are implicitly imported.
> Hence you would have something like the following code. This is not far
> different from the importall today, except that the exports are
> automatically restricted.
>
> using MyMath         # Imports only those functions which include types
> defined in MyMath
> import MyMath.*      # Imports all other  functions  defined in MyMath
> import MyMath.afunc  # Imports  one  function
> import MyOther.afunc # Fails collides with MyMath.afunc
>
>
>
>
>
>
> On Wednesday, April 22, 2015 at 4:40:03 PM UTC-4, Jeff Bezanson wrote:
>>
>> That rule seems extremely restrictive to me. It would be very common,
>> for example, to create a library of functions that operate on standard
>> data types like numbers and arrays. I don't see that we can exclude
>> that kind of use.
>>
>> Also, printing a warning is not the key part of #4345. The important
>> part is that you'd have to qualify names in that case, which is the
>> same thing that would happen if `export`ing the names were disallowed.
>>
>>
>> On Wed, Apr 22, 2015 at 8:47 AM, Michael Francis <[email protected]>
>> wrote:
>> > I read through the issues / threads ( and some others )
>> >
>> > https://github.com/JuliaLang/julia/issues/2327
>> > https://github.com/JuliaLang/julia/issues/4345
>> >
>> > I'm not sure that the either the SuperSecretBase or the warning are the
>> > correct approach. I'd like to propose a counter which is a very simple
>> > rule.
>> >
>> > "You can only export functions from a module where they reference at
>> > least
>> > one type defined in the module."
>> >
>> > There may have to be a slight tweak for Base, though it is not hard to
>> > argue
>> > that the primitive types are defined in Base.
>> >
>> > so
>> >
>> > module Module1
>> > type Bar end
>> > my( b::Bar ) = 1
>> >
>> > export my       # fine exports to the global space
>> > end
>> >
>> > module Module2
>> > type Foo end
>> > my() = 1
>> >
>> > export my       # ERROR exporting function which does not reference
>> > local
>> > type
>> > end
>> >
>> > module Module3
>> > type Wow end
>> > my( w::Wow ) = 1
>> > my() = 1
>> > end
>> > export my       # Is an ERROR I can not export a function which does not
>> > reference a local type
>> > end
>> >
>> > So in the example provided my Mike above, multiple dispatch would do the
>> > right thing. If I also want to define a function for value in my module
>> > it
>> > would work consistently against the types I define. We don't have to
>> > perform
>> > recursive exports and import usage should be reduced.
>> >
>> > If you want to define an empty function you can do so with a default arg
>> > module Module4
>> > type Zee end
>> > my( ::Type{Zee} = Zee ) = 1
>> > export my       # Works, but I can select against it using multiple
>> > dispatch
>> > by providing the last arg
>> > end
>> >
>> >
>> > I can't convince myself that exporting Types in general (nor macros) is
>> > a
>> > good idea.
>> >
>> > A tweak may be to add C# like module alias syntax, which is just
>> > syntactic
>> > sugar over what we have ( except that we would likely want the
>> > definition of
>> > MY to be const in the scope.
>> >
>> > MY = using Foo.Bar.ReallyLongModuleName
>> > t = MY.Type()
>> > my( t )
>> >
>> >
>> > Thoughts ?
>> >
>> >
>> > I'm sure there is something I have missed, but this simple rule would
>> > seem
>> > to encourage multiple dispatch and support the development of modules.
>> >
>> > On Tuesday, April 21, 2015 at 1:07:40 PM UTC-4, Jeff Bezanson wrote:
>> >>
>> >> We're planning to do something about this: #4345. When `using` two
>> >> modules with conflicting names, we should do something other than pick
>> >> one depending on order. Most likely we will print a warning, and
>> >> require uses of the name to be qualified.
>> >>
>> >> If the two modules really do want to define different methods for the
>> >> same function, then either one has to import the other, or you have to
>> >> use your SuperSecretBase approach.
>> >>
>> >> On Tue, Apr 21, 2015 at 9:37 AM, Michael Turok <[email protected]>
>> >> wrote:
>> >> > Note that this can be made to work by tearing a page from Base:  we
>> >> > can
>> >> > a
>> >> > module (SuperSecretBase), that defines a stub value() function. We
>> >> > then
>> >> > use
>> >> > importall SuperSecretBase in each of Foo and Bar.    But this means
>> >> > that
>> >> > any
>> >> > module we create would need to declare its functions into
>> >> > SuperSecretBase.
>> >> >
>> >> > julia> workspace() ; include("mike.jl")
>> >> >
>> >> > julia> using Foo
>> >> >
>> >> > julia> using Bar
>> >> >
>> >> > julia> value(Bar.BarType())
>> >> > "Bar::value"
>> >> >
>> >> > julia> value(Foo.FooType())
>> >> > "Foo::value"
>> >> >
>> >> > julia>
>> >> >
>> >> > Modified code follows:
>> >> >
>> >> > module SuperSecretBase
>> >> > value() = nothing
>> >> > export value
>> >> > end
>> >> >
>> >> > # ------------------------------
>> >> >
>> >> > module Foo
>> >> >
>> >> > importall SuperSecretBase
>> >> >
>> >> > importall Base
>> >> > type FooType end
>> >> >
>> >> > value(x::FooType) = "Foo::value"
>> >> > get(x::FooType) = "Foo::get"
>> >> >
>> >> > export value
>> >> >
>> >> > end
>> >> >
>> >> > # ------------------------------
>> >> >
>> >> > module Bar
>> >> >
>> >> > importall SuperSecretBase
>> >> >
>> >> > importall Base
>> >> >
>> >> > type BarType end
>> >> >
>> >> > value(x::BarType) = "Bar::value"
>> >> > get(x::BarType) = "Bar::get"
>> >> >
>> >> > export value
>> >> >
>> >> > end
>> >> >
>> >> >
>> >> >
>> >> >
>> >> > On Tuesday, April 21, 2015 at 9:26:01 AM UTC-4, Michael Turok wrote:
>> >> >>
>> >> >> Hi,
>> >> >>
>> >> >> What is the idiomatic way to create a function value() in different
>> >> >> modules, dispatched on different arguments, without getting the
>> >> >> warning/error about conflicting with an existing identifier?
>> >> >>
>> >> >> It seems like there is an order dependency with the example below.
>> >> >> Seems
>> >> >> like the 2nd module defines value(), unless you had already used
>> >> >> value()
>> >> >> prior to importing the 2nd module.
>> >> >>
>> >> >> Note that if I do the same with get() a function defined in Base, I
>> >> >> don't
>> >> >> get an error.
>> >> >>
>> >> >> Code and output from julia REPL below.
>> >> >>
>> >> >> Any help appreciated,
>> >> >> Michael
>> >> >>
>> >> >> # this is mike.jl
>> >> >>
>> >> >> # ------------------------------
>> >> >> module Foo
>> >> >> # ------------------------------
>> >> >> importall Base
>> >> >> type FooType end
>> >> >>
>> >> >> value(x::FooType) = "Foo::value"
>> >> >> get(x::FooType) = "Foo::get"
>> >> >>
>> >> >> export value
>> >> >>
>> >> >> end
>> >> >>
>> >> >> # ------------------------------
>> >> >> module Bar
>> >> >> # ------------------------------
>> >> >> importall Base
>> >> >>
>> >> >> type BarType end
>> >> >>
>> >> >> value(x::BarType) = "Bar::value"
>> >> >> get(x::BarType) = "Bar::get"
>> >> >>
>> >> >> export value
>> >> >>
>> >> >> end
>> >> >>
>> >> >> Using this in the REPL:
>> >> >> julia> workspace() ; include("mike.jl")
>> >> >>
>> >> >> julia> using Foo
>> >> >>
>> >> >> julia> value(Foo.FooType())
>> >> >> "Foo::value"
>> >> >>
>> >> >> julia> using Bar
>> >> >> Warning: using Bar.value in module Main conflicts with an existing
>> >> >> identifier.
>> >> >>
>> >> >> julia> value(Bar.BarType())
>> >> >> ERROR: `value` has no method matching value(::BarType)
>> >> >>
>> >> >> # -----------------------------------------------------
>> >> >>
>> >> >> julia> workspace() ; include("mike.jl")
>> >> >>
>> >> >> julia> using Foo
>> >> >>
>> >> >> julia> using Bar
>> >> >>
>> >> >> julia> value(Foo.FooType())
>> >> >> ERROR: `value` has no method matching value(::FooType)
>> >> >>
>> >> >> julia> value(Bar.BarType())
>> >> >> "Bar::value"
>> >> >>
>> >> >> # -----------------------------------------------------
>> >> >>
>> >> >> julia> workspace() ; include("mike.jl")
>> >> >>
>> >> >> julia> using Bar
>> >> >>
>> >> >> julia> using Foo
>> >> >>
>> >> >> julia> value(Foo.FooType())
>> >> >> "Foo::value"
>> >> >>
>> >> >> julia> value(Bar.BarType())
>> >> >> ERROR: `value` has no method matching value(::BarType)
>> >> >>
>> >> >> julia>

Reply via email to