Hey, Sorry I'm not sure what you're referring too.
Just to clarify. I have written 3 functions in the first subject. The first function uses run time dispatch, the second use sub-auxiliary functions at every differing line, the third uses the @eval style. I like the syntax of the first function, but I want the performance of the second or third function (ie compile time dispatch) In my second message, have posted a 4th and 5th way, with a syntax close to the first function (that I like), but with compile-time dispatch. The 4th method is just another way to write the 3rd method. The 5th method uses @generated, and I understand it may be overkill (at least for the simple example!). I'm not sure which one you are advising me to use. I think you're referring to the second one, right? But I really dont like the idea of defining new functions for every differing line between the two methods (including finding meaningful new function names). Another issue is that, if a diverging line involves a lot of local variables, all of them must be passed to the function (including typically a loop counter), which makes the whole thing unreadable. Thanks for the explanation of the @eval use in Base, I did not realize this. On Tuesday, September 29, 2015 at 10:33:07 PM UTC-4, Jameson wrote: > > As Stefan mentioned, the `@generated` function below is equivalent to the > first function you posted, except that it is worse style since it is not > extensible, will generally require more memory, it is less readable (and it > seems to be giving the wrong answer for N > 2 and N == 0?) > > The Julia-style is to use the second function that you posted, since it is > extensible and provides an appropriate separation (abstraction) between > behavior and implementation details. > > The `@eval`-style function is used heavily in Base to generate a variety > of ccall's that can be heavily templated. It doesn't make sense to use the > usual Julia-style for these functions since the c-functions themselves are > not extensible. So this style code is most appropriate when your code is > providing language interoperability with a static language. It isn't > particularly well suited for writing code within Julia since it is rather > verbose, the compile-time and runtime constructs get mixed rather awkwardly > in the same code, and some essential parts of the code (in this case `t`), > get separated pretty far from their use sites > > > On Tue, Sep 29, 2015 at 9:17 PM Matt <[email protected] <javascript:>> > wrote: > >> Thanks for answering. Sorry I deleted my question after finding what I >> wanted. If some people are interested, I like the two solutions below: >> >> for t in (Vector, Matrix) >> @eval begin >> function f2(x::$t) >> println("I'm an array") >> $(t == Vector ? :(println("I'm a vector")) : :(println("I'm >> a matrix"))) >> end >> end >> end >> >> or even >> >> @generated function f{T, N}(x::Array{T, N}) >> quote >> println("I'm an array") >> $(N == 1 ? :(println("I'm a vector")) : :(println("I'm a >> matrix"))) >> end >> end >> >> >> >> On Tuesday, September 29, 2015 at 8:57:10 PM UTC-4, Stefan Karpinski >> wrote: >> >>> The branch on the first version will be eliminated. The second version >>> is far more idiomatic, however. Consider that the second version is >>> trivially extensible to more types while the first version cannot be >>> extended at all. >>> >>> On Tuesday, September 29, 2015, Matt <[email protected]> wrote: >>> >>>> I want to write a method that is very similar between two types, with >>>> slight divergences. I'd like to write it avoiding code duplication. >>>> >>>> To take a simple example, let's say that the two types are Vector and >>>> Matrix. The method must print "I'm an array" for the two types, and then >>>> prints "I'm a vector" if the object is a vector, "I'm a matrix" if the >>>> object is a matrix. >>>> >>>> One way write this method is to use a "run time" dispatch >>>> >>>> function f{T, N}(x::Array{T, N}) >>>> println("I'm an array") >>>> if N == 1 >>>> println("I'm a vector") >>>> elseif N == 2 >>>> println("I'm a matrix") >>>> end >>>> end >>>> f2(rand(10, 10)) >>>> @code_warntype f2(rand(10, 10)) >>>> >>>> A way to dispatch at compile time is to define as many auxiliary >>>> function as there are differing lines >>>> >>>> function _ansfunction(x::Vector) >>>> println("I'm a vector") >>>> end >>>> function _ansfunction(x::Matrix) >>>> println("I'm a matrix") >>>> end >>>> function f1(x) >>>> println("I'm an array") >>>> _ansfunction(x) >>>> end >>>> f1(rand(10, 10)) >>>> @code_warntype f1(rand(10, 10)) >>>> >>>> Another solution would be to iterate through two NTuples, where N is >>>> the number of differing lines >>>> >>>> for (t, x) in ((:Vector, :(println("I'm a vector"))), >>>> (:Matrix, :(println("I'm a Matrix")))) >>>> @eval begin >>>> function f2(x::$t) >>>> println("I'm an array") >>>> $x >>>> end >>>> end >>>> end >>>> f2(rand(10, 10)) >>>> @code_warntype f2(rand(10, 10)) >>>> >>>> >>>> These two last solutions work, but I really prefer the syntax of first >>>> solution : it allows to write the differing lines exactly at the place >>>> they're needed, when they're needed. It really starts to mattes when there >>>> are a few differing lines. Is there a syntax as clear as the first >>>> solution, but that "branch" at compile time? >>>> >>>
