Dimitris
Dimitris

Reputation: 207

How can I shorten a type in the body of a function

Best be explained by an example:

I define a type

type myType
    α::Float64
    β::Float64
end
z = myType( 1., 2. )

Then suppose that I want to pass this type as an argument to a function:

myFunc( x::Vector{Float64}, m::myType ) =
    x[1].^m.α+x[2].^m.β

Is there a way to pass myType so that I can actually use it in the body of the function in a "cleaner" fashion as follows:

    x[1].^α+x[2].^β

Thanks for any answer.

Upvotes: 2

Views: 148

Answers (3)

Tasos Papastylianou
Tasos Papastylianou

Reputation: 22245

UPDATE: My original answer was wrong for a subtle reason, but I thought it was a very interesting bit of information so rather than delete it altogether, I'm leaving it with an explanation on why it's wrong. Many thanks to Fengyang for pointing out the global scope of eval! (as well as the use of $ in an Expr context!)

The original answer suggested that:

[eval( parse( string( i,"=",getfield( m,i)))) for i in fieldnames( m)]

would return a list comprehension which had assignment side-effects, since it conceptually would result in something like [α=1., β=2., etc]. The assumption was that this assignment would be within local scope. However, as pointed out, eval is always assessed at global scope, therefore the above one-liner does not do what it's meant to. Example:

julia> type MyType
         α::Float64
         β::Float64
       end

julia> function myFunc!(x::Vector{Float64}, m::MyType)
         α=5.; β=6.; 
         [eval( parse( string( i,"=",getfield( m,i)))) for i in fieldnames( m)]
         x[1] = α; x[2] = β; return x
       end;

julia> myFunc!([0.,0.],MyType(1., 2.))
2-element Array{Float64,1}:
 5.0
 6.0

julia> whos()
                        MyType    124 bytes  DataType
                        myFunc      0 bytes  #myFunc
                             α      8 bytes  Float64
                             β      8 bytes  Float64

I.e. as you can see, the intention was for the local variables α and β to be overwritten, but they didn't; eval placed α and β variables at global scope instead. As a matlab programmer I naively assumed that eval() was conceptually equivalent to Matlab, without actually checking. Turns out it's more similar to the evalin('base',...) command.

Thanks again to Fengyand for giving another example of why the phrase "parse and eval" seems to have about the same effect on Julia programmers as the word "it" on the knights who until recently said "NI". :)

Upvotes: 1

Chris Rackauckas
Chris Rackauckas

Reputation: 19152

One way is to use dispatch to a more general function:

myFunc( x::Vector{Float64}, α::Float64, β::Float64) = x[1].^α+x[2].^β
myFunc( x::Vector{Float64}, m::myType = myFunc(x,m.α,m.β)

Or if your functions are longer, you may want to use Parameters.jl's @unpack:

function myFunc( x::Vector{Float64}, m::myType )
  @unpack m: α,β #now those are defined
  x[1].^α+x[2].^β
end

The overhead of unpacking is small because you're not copying, it's just doing a bunch of α=m.α which is just making an α which points to m.α. For longer equations, this can be a much nicer form if you have many fields and use them in long calculations (for reference, I use this a lot in DifferentialEquations.jl).

Edit

There's another way as noted in the comments. Let me show this. You can define your type (with optional kwargs) using the @with_kw macro from Parameters.jl. For example:

using Parameters
@with_kw type myType
  α::Float64 = 1.0 # Give a default value
  β::Float64 = 2.0 
end
z = myType() # Generate with the default values

Then you can use the @unpack_myType macro which is automatically made by the @with_kw macro:

function myFunc( x::Vector{Float64}, m::myType )
  @unpack_myType m
  x[1].^α+x[2].^β
end

Again, this only has the overhead of making the references α and β without copying, so it's pretty lightweight.

Upvotes: 7

Michael Ohlrogge
Michael Ohlrogge

Reputation: 10990

You could add this to the body of your function:

(α::Float64, β::Float64) = (m.α, m.β)

Upvotes: 1

Related Questions