# program in Julia, testing multiple dispatch, its most interesting feature # julia numbers.jl executes the script mutable struct Rat # Rational number n::Int d::Int end plus(x::Int,y::Int) = x+y plus(x::Int,y::Rat) = Rat(x*y.d+y.n,y.d) plus(x::Rat,y::Rat) = let temp = Rat(x.n*y.d+y.n*x.d, x.d*y.d) reduce(temp) # forward reference ok temp end plus(x::Rat,y::Int) = plus(y,x) # this line must be here before called half = Rat(1,2) quarter = Rat(1,4) third = Rat(1,3) gcd(a,b) = if a==0 b else gcd(b%a,a) end function reduce(x::Rat) d = gcd(x.n,x.d) x.n /= d x.d /= d end sum = plus(half,quarter) println(sum) println(plus(1,half)) println(plus(quarter,1)) # error without explict clause below #plus(x::Rat,y::Int) = plus(y,x) # this line can't be beneath usage! # Mathematically, a function from domain A to codomain B is a relation f # such that, FOR ALL x in A, there exists a unique y in B such that f(x)=y # Notice the "for all" part of the definition. If you don't define what the # "function" does for all possible values of type A, then it can't be called # a function. A typed programming language must make sure that what we # define are at least functions. Here, the domain of the 'plus' function # appears to be: Union(Int,Rat) x Union(Int,Rat) : the cartesian product of # the two unions. From this perpective, Julia allows incomplete definitions # of functions. Julia may claim that what it's really doing is runtime # overloading of a function name, which can dispatch to the correct function # restricted to a certain type. But the practical consequences are the same: # there's no way to statically guarantee if a function will run or crash. times(x::Int, y::Int) = x*y times(x::Int, y::Rat) = let tmp = Rat(x*y.n,y.d) reduce(tmp) (tmp.d==1) ? tmp.n : tmp # can return values of different types end f(x,y) = times(x,y) # times can be called in variety of contexts... # f is a generic (polymorphic) function. But will it always return something? println( f(2,3) ) # ok println( f(3,Rat(1,2)) ) # ok, returns Rat println( f(2,Rat(1,2)) ) # ok, returns Int #println( f(Rat(1,3),1) ) # not ok. a statically typed language won't allow this # But in Julia there's no way to check this kind of consistency before the code # runs.