Also, both Stefan and you mention that the branching is eliminated in the
first method. But if if I use on the first version
@code_warntype f(rand(10, 10))
Body:
begin # none, line 2:
(Base.println)(Base.STDOUT,"I'm an array")::Any # line 3:
unless 2 === 1::Bool goto 0 # line 4:
return (Base.println)(Base.STDOUT,"I'm a vector")::Any
goto 2
0: # line 5:
unless 2 === 2::Bool goto 1 # line 6:
return (Base.println)(Base.STDOUT,"I'm a matrix")::Any
goto 2
1:
return
2:
end::Any
while all other methods do eliminate branching:
Body:
begin # none, line 2:
(Base.println)(Base.STDOUT,"I'm an array")::Any # line 3:
return (Base.println)(Base.STDOUT,"I'm a matrix")::Any
end::Any
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] <javascript:>>
> 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?
>>
>