@Stefan: Out of curiosity, do you see any inherent problems in having Julia 
automatically create such an "empty" function f in the module that imports 
both Foo.f and Bar.f and then merge the (unambiguous) methods into the 
automatically created f? (Or just automatically merge unambiguous methods 
to whatever function already has the name f in the importing module.) Or is 
it just not in the style of Julia (or in the vision of its creators) to do 
something like that?

Again, I'm just asking out of curiosity, as I'm finding this conversation 
an interesting vehicle for learning about issues of scope and naming in 
Julia.

On Wednesday, April 29, 2015 at 4:41:38 PM UTC-4, Stefan Karpinski wrote:
>
> Tom, this is a very legitimate concern. A simple solution is to have a 
> coding standard not to use `using` when writing packages. Google has 
> created coding standards for both C++ and Python, which are now widely used 
> beyond the company.
>
> Automatic function merging goes in the opposite direction: with this 
> feature it becomes impossible to even say which package a function comes 
> from – it's not even a meaningful question anymore. That is the point of 
> Jeff's Base.sin versus Transgression.sin example – map(sin, [1.0, "greed", 
> 2pi, "sloth"]). There is no answer to the question of which of the function 
> Base.sin and Transgreassion.sin the `sin` function refers to – it can only 
> refer to some new `sin` that exists only in the current module and calls 
> either Base.sin or Transgressions.sin depending on the runtime values of 
> its arguments. Perhaps this can be made clearer with an even nastier 
> example, assuming hypothetical code with function merging:
>
> module Foo
>     export f
>     immutable F end
>     f(::F) = "this is Foo"
> end
>
> module Bar
>     export f
>     immutable B end
>     f(::B) = "this is Bar"
> end
>
> julia> using Foo, Bar
>
> julia> f(rand(Bool) ? Foo.F() : Bar.B()) # which `f` is this?
>
>
> Which `f` is intended to be called here? It cannot be statically 
> determined – it's not well-defined since it depends on the value of 
> rand(Bool). Some dynamic languages are Ok with this kind of thing, but in 
> Julia, the *meaning* of code should be decidable statically even if some of 
> the behavior may be dynamic. Compare with this slightly different version 
> of the above code (works on 0.4-dev):
>
> module Sup
>     export f
>     f(::Void) = nothing # declare generic function without a la #8283 
> <https://github.com/JuliaLang/julia/issues/8283>
> end
>
> module Foo
>     export f
>     import Sup: f
>     immutable F end
>     f(::F) = "this is Foo"
> end
>
> module Bar
>     export f
>     import Sup: f
>     immutable B end
>     f(::B) = "this is Bar"
> end
>
> julia> using Foo, Bar
>
> julia> f(rand(Bool) ? Foo.F() : Bar.B())
>
>
> Why is this ok, while the previous code was problematic? Here you can say 
> which `f` is called: Foo and Bar share `f` so the answer is well-defined – 
> `f` is always `Sup.f`.
>
> On Wed, Apr 29, 2015 at 3:36 PM, Tom Breloff <[email protected] 
> <javascript:>> wrote:
>
>> Stefan:  I agree that typing Distributions.Normal(0,1) in the REPL when 
>> you're just doing data exploration is really frustrating.  However, when 
>> you're building a package or a larger system, it can be really important to 
>> either explicitly qualify your types/functions or to explicitly "import 
>> Distributions: Normal".  Frequently I'll be looking at some code within a 
>> large package with a call to "Normal", but I don't know what function will 
>> be called here.  If I do some type of explicit importing, then I can do a 
>> simple find command on my directory to figure out what package it may have 
>> been defined in.  If I did a "using", then I have a lot more searching to 
>> figure out the correct function.  Not to mention the silent overwriting of 
>> functions by "using" different modules can cause unexpected problems.  For 
>> that reason, I try to keep "using" to an absolute minimum in most of my 
>> code.
>>
>> On Wednesday, April 29, 2015 at 2:49:34 PM UTC-4, Stefan Karpinski wrote:
>>>
>>> This scheme seems overly focused on object-oriented programming styles 
>>> at the cost of making other programming styles much more inconvenient. In 
>>> an o-o language that might be fine, but non-o-o styles are quite common in 
>>> Julia. The `connect` example keeps coming up because it is one of those 
>>> cases where o-o works well. That is not the norm in numerical package, 
>>> however. This proposal would, for example, make using Distributions 
>>> <https://github.com/JuliaStats/Distributions.jl> a nightmare – you'd 
>>> have to explicitly import almost everything that it exports 
>>> <https://github.com/JuliaStats/Distributions.jl/blob/dacb401cfcfc7463f69af0009497960038b25dd5/src/Distributions.jl#L18-L238>
>>>  to 
>>> use. That includes type constructors for distributions etc., since those 
>>> are themselves (basically) generic functions and their arguments are just 
>>> built-ins. Instead of doing this:
>>>
>>> using Distributions
>>> X = Normal(0.0, 1.0)
>>> p = pdf(X, 0.1)
>>>
>>>
>>> you'd have to do this:
>>>
>>> using Distributions
>>> X = Distributions.Normal(0.0, 1.0)
>>> p = Distributions.pdf(X, 0.1)
>>>
>>>
>>> Or you'd have to explicitly import every Distributions type and generic 
>>> stats function that you want to use. Instead of being able to write `using 
>>> Distributions` and suddenly having all of the stats stuff you might want 
>>> available easily, you'd have to keep qualifying everything or explicitly 
>>> importing it. Both suck for interactive usage – and frankly even for 
>>> non-interactive usage, qualifying or explicitly importing nearly every name 
>>> you use is a massive and unnecessary hassle.
>>>
>>> On Wed, Apr 29, 2015 at 2:06 PM, Michael Francis <[email protected]> 
>>> wrote:
>>>
>>>> I would expect the user to explicitly import those method, I did not 
>>>> preclude their existence. And it would be quite reasonable to support the 
>>>> existing import all syntax hence 
>>>>
>>>> using MyModule
>>>> ^ imports only those functions which explicitly reference user types 
>>>> defined in the module 
>>>> importall MyModule.Extensions
>>>> ^imports the additional functionality on base types
>>>>
>>>> if I subsequently import another function which conflicts then we throw 
>>>> an error. This would mean that the vast majority of non conflicting 
>>>> functions can be trivially exported and used without a namespace qualifier 
>>>> and extensions to base types would also work, but with the name collision 
>>>> check in place. 
>>>>
>>>> I don't believe this violates the expression problem ? 
>>>>
>>>>
>>>> On Wednesday, April 29, 2015 at 1:55:14 PM UTC-4, Stefan Karpinski 
>>>> wrote:
>>>>>
>>>>>
>>>>> I made the point at the outset that it isn't hard (or expensive) if 
>>>>>> the *exported *functions from a module *must reference types defined 
>>>>>> in that module*. Hence the suggestion that module developers should 
>>>>>> only be able to export functions which reference 
>>>>>> owned/hard/contained/user 
>>>>>> types.
>>>>>>
>>>>>
>>>>> Unless I'm misunderstanding, this is a very limiting restriction. It 
>>>>> would mean, for example, that you can't define and export a generic 
>>>>> square(::Number) function. That's a silly example, but it's completely 
>>>>> standard for packages to export new functions that operate on 
>>>>> pre-existing 
>>>>> types that don't dispatch on any type that "belongs" to the exporting 
>>>>> module.
>>>>>
>>>>> Another way of looking at this is that such a restriction would 
>>>>> prevent solving half of the expression problem 
>>>>> <http://en.wikipedia.org/wiki/Expression_problem>. In object-oriented 
>>>>> languages, extending existing operations to new types is easily done via 
>>>>> subtyping, but adding new operations to existing types is awkward or 
>>>>> impossible. In functional languages, adding new operations to existing 
>>>>> types is easy, but extending existing operations to new types is awkward 
>>>>> or 
>>>>> impossible. Multiple dispatch lets you do both easily and intuitively – 
>>>>> so 
>>>>> much so that people can easily forget why the expression problem was a 
>>>>> problem in the first place. Preventing the export of new functions 
>>>>> operating only on existing types would hobble the language, making it no 
>>>>> more expressive than traditional object-oriented languages.
>>>>>
>>>>
>>>
>

Reply via email to