Git Product home page Git Product logo

virtual.jl's Introduction

Virtual

Virtual call in Julia, and calls are de-virtualized if possible!

Stable Dev Build Status

  • Requirement: Julia >= 1.6 (You can build this package for Julia 1.1+ by invoking bash.sh)

This package can be regarded as a generalization to ValSplit.jl. Virtual functions created with this package bring us the following features:

  • No virtual call when it's statically decidable!
  • Otherwise, use an efficient virtual call that is slightly faster than a manual if-else split!
  • Support multiple dispatch, i.e., not single dispatch on the first parameter!

This package aims to address an issue in practice: container manipulation used to be considerably slow in Julia, if the element type is abstract.

The following code shows how Virtual.jl speeds up multiple dispatch in a factor of 40 when processing containers with abstract element types.

using Virtual, BenchmarkTools
abstract type Animal end
struct Dog <: Animal end
struct Tiger <: Animal end
struct Duck <: Animal end

@virtual fast_func(x::Animal, y::Int) = error("No default method for score!")
@override fast_func(x::Dog, y::Int) = 2 + y
@override fast_func(x::Tiger, y::Int) = 3 + y
@override fast_func(x::Duck, y::Int) = 4 + y

dyn_func(x::Animal, y::Int) = error("No default method for score!")
dyn_func(x::Dog, y::Int) = 2 + y
dyn_func(x::Tiger, y::Int) = 3 + y
dyn_func(x::Duck, y::Int) = 4 + y

manual_func(x::Animal, y::Int) =
    if x isa Dog
        2 + y
    elseif x isa Tiger
        3 + y
    elseif x isa Duck
        4 + y
    else
        error("No default method for score!")
    end

const samples = Animal[Dog(), Duck(), Tiger()]
animals = Animal[samples[rand(1:3)] for i = 1:100]

function sum_score(score_func, xs::AbstractVector{Animal})
    s = 0
    for x in xs
        s += score_func(x, 3)
    end
    return s
end

@info "fast_func via Virtual.jl"
display(@benchmark(sum_score(fast_func, animals)))
@info "manual split by hand"
display(@benchmark(sum_score(manual_func, animals)))
@info "dyn_func by dynamic multiple dispatch"
display(@benchmark(sum_score(dyn_func, animals)))

The results are given as follow:

Limitations

  1. @override methods must have a more specific signature than that of the default method. I'm planning to add checkers for this.

    @virtual f(x::Number, y::Number) = 0
    
    # wrong: Tuple{Float64, Any} <: Tuple{Number, Number} === false
    @override f(x::Float64, y) = x * 3
    
    # correct: Tuple{Float64, Number} <: Tuple{Number, Number} === true
    @override f(x::Float64, y::Number) = x * 3
  2. Variadic parameters and keyword parameters are not supported (default parameters are supported!)

    # wrong
    @virtual g(x::Number; y::Number = 1) = y
    ERROR: LoadError: virtual function does not take keyword parameters
    
    # correct, using default parameters
    @virtual g(x::Number, y::Number = 1) = y
    
    # so far a strange behavior to use default parameters in virtual functions
    @override g(x::Int, y::Int) = x + y
    
    g(2)   # 2 + 1 => 3
    g(2.0) # 1
    
    @virtual h(xs...) = 1
    ERROR: LoadError: virtual function does not take variadic parameters

virtual.jl's People

Contributors

thautwarm avatar moelf avatar

Stargazers

Robert avatar Orestis Ousoultzoglou avatar Arjit Seth avatar ebigram avatar Páll Haraldsson avatar Yueh-Hua Tu avatar Cameron Bieganek avatar pixor avatar Chad Scherrer avatar Mirek Kratochvil avatar Sebastian Micluța-Câmpeanu avatar Ujjwal Panda avatar Kun Chen avatar Suavesito avatar Yue Yang avatar Zachary P Christensen avatar Joshua Niemelä avatar Frederic Freyer avatar John Lapeyre avatar Matthew LeMay avatar  avatar St. Elmo Wilken avatar songjhaha avatar Nikita avatar Hans Würfel avatar Qingyu Qu avatar Johnny Chen avatar Peter avatar Qi Zhang avatar Jan Weidner avatar Gabriel Wu avatar  avatar Hai Zhu avatar Guilherme Bodin avatar Guillaume Dalle avatar Elias Carvalho avatar Chris Geoga avatar Daniel avatar Yingbo Ma avatar ChangXin Sun avatar Lîm Tsú-thuàn avatar

Watchers

James Cloos avatar  avatar  avatar

Forkers

moelf

virtual.jl's Issues

Any chance to support Parametric Methods?

With your Aminal example

@virtual fast_func(x::Animal, y::T) where T = error("No default method for score!")

one gets the error: LoadError: invalid function expression: (fast_func(x::Animal, y::T) where T) = begin

The same when overwriting with a Pametric type, for example:

struct Dog{R} <: Animal end
@override fast_func(x::Dog{R}, y::Int) where R  = 2 + y

one gets the error LoadError: invalid function expression: (fast_func(x::Dog{R}, y::Int) where R) = begin

error: `setfield!` should not be changed

[ Info: Precompiling Geom4hep [eb5d0804-93e0-431a-a4d4-b4f95b95575a]
ERROR: LoadError: setfield! fields of Types should not be changed
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:35
  [2] setproperty!(x::Type, f::Symbol, v::Symbol)
    @ Base ./Base.jl:34
  [3] parse_function_header!(ln::LineNumberNode, self::Virtual.FuncInfo, header::Expr; is_lambda::Bool, allow_lambda::Bool)
    @ Virtual C:\Users\twshe\Desktop\Git\Virtual\src\reflection.jl:230
  [4] parse_function(ln::LineNumberNode, ex::Expr; fallback::Virtual.Undefined, allow_short_func::Bool, allow_lambda::Bool)
    @ Virtual C:\Users\twshe\Desktop\Git\Virtual\src\reflection.jl:186
  [5] var"@override"(__source__::LineNumberNode, __module__::Module, func_def::Any)
    @ Virtual ~/.julia/packages/Virtual/OLENd/src/Virtual.jl:256
  [6] include(mod::Module, _path::String)
    @ Base ./Base.jl:419
  [7] include(x::String)
    @ Geom4hep ~/Documents/github/Geom4hep/src/Geom4hep.jl:1

is this problem of how I'm using the package or Virtual.jl doesn't work on 1.8?

adding checkers for invalid `@override` or automatically narrow to fit `@virtual`'s signature

Option 1:

@virtual fast_func(x::Animal, y::Int) = error("No default method for score!")

@override fast_func(x::Dog, y) = 2 + y
Error: the signature 'fast_func(x::Dog, y)' has signature `Tuple{Dog, Any}` which is not more specific than `Tuple{Animal, Int}`

Option 2:

@virtual fast_func(x::Animal, y::Int) = error("No default method for score!")

@override fast_func(x::Dog, y) = 2 + y
# automatically narrow to
@override fast_func(x::Dog, y::typeintersect(Int, Any)) = 2 + y

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.