Quantcast

Interfaces and Lexical vs Dynamic Scope

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Interfaces and Lexical vs Dynamic Scope

Joshua Ballanco
Hi all!

Apologies in advance if there’s already a ticket where this discussion should be had (pointers to such greatly appreciated).

I was recently thinking about what interfaces might eventually look like, and specifically one of the ideas that was batted about during the JuliaCon hack day. Writing a function that takes an array-like thing might be implemented as:

    function foo(myarray::ANY{getindex(), setindex(), iterate()})
      #…
    end

where the functions mentioned in the type signature are required to exist for any argument passed to the function.

One potential “big win” I see in this sort of interface is that it gives the programmer the opportunity to massage types that normally wouldn’t qualify for the interface by providing custom implementations for any missing methods. For example, say you had an immutable array-like that didn’t implement `setindex()` on its own. One could, if they desired, provide an implementation of `setindex()` that was a no-op, or returned a copy with the desired update, etc.

What I particularly like with this approach is that instead of having to implement many variants of a method to handle different types, one could write the core logic in a single, clearly understandable function and segregate the custom edge-case logic elsewhere.

This works well if the non-adhering type might be passed to the method you are writing and you can add the missing methods in the same module. e.g.:

    module Bar
      setindex(a::ImmutableArray) = #…
      function foo(myarray::ANY{getindex(), setindex(), iterate()})
        #…
      end
    end

But what if the code you are writing is merely glue between a non-adhering type and a function that expects a particular interface? e.g.:

    module Bar
      function foo(myarray::ANY{getindex(), setindex(), iterate()})
        #…
      end
    end

    module Qux
      setindex(a::ImmutableArray) = #…
      function doit(somearray::ANY)
        Bar.foo(somearray)
        #…
      end
    end

    module Main
      data = ImmutableArray()
      Qux.doit(data)
    end

In this case I think I’d like `Bar.foo()` to use `Qux.setindex()` when called from within `Qux` with an `ImmutableArray`…but this seems like treading on dangerous scoping territory!

I don’t have a solution to propose at the moment, but I wanted to raise the issue because I see some potential parallels with Ruby’s refinements. The concept of refinements is potentially rather powerful, but Ruby’s implementation was dogged by a literally years-long debate over how scoping should work and how to implement such scoping without completely crippling performance.

Cheers,

Josh
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Interfaces and Lexical vs Dynamic Scope

Joshua Ballanco
 On July 21, 2016 at 21:37:00, Joshua Ballanco
([hidden email](mailto:[hidden email])) wrote:

> But what if the code you are writing is merely glue between a non-adhering type and a function that expects a particular interface? e.g.:
>
> module Bar
> function foo(myarray::ANY{getindex(), setindex(), iterate()})
> #…
> end
> end
>
> module Qux
> setindex(a::ImmutableArray) = #…
> function doit(somearray::ANY)
> Bar.foo(somearray)
> #…
> end
> end
>
> module Main
> data = ImmutableArray()
> Qux.doit(data)
> end
>
> In this case I think I’d like `Bar.foo()` to use `Qux.setindex()` when called from within `Qux` with an `ImmutableArray`…but this seems like treading on dangerous scoping territory!

Upon further consideration, I think it may have been wrong to limit
this to some potential implementation of interfaces/protocols. Indeed,
being able to inject a scope into a called method could potentially be
useful today, and is very analogous to the situation of Ruby’s
refinements. That is, say you wanted to provide a custom
implementation of `capitalize(s::String)` to be used by methods you
call. How might this be achieved? In Ruby this looks like

    module MyStringExtension
      refine String do
        def capitalize
          #…
        end
      end
    end

    class MyClass
      using MyStringExtension
      “foo”.capitalize
    end

Would it be useful to consider something similar for Julia?

Cheers,

Josh
Loading...