mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 17:41:41 +00:00
Expanded Type and Multiple Dispatch sections, and added more dispatch examples. Also added link to mailing list.
This commit is contained in:
parent
7ec6479a3c
commit
364c367ff3
@ -479,49 +479,104 @@ filter(x -> x > 5, [3, 4, 5, 6, 7]) #=> [6, 7]
|
|||||||
[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13]
|
[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13]
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
## 5. Types and Multiple-Dispatch
|
## 5. Types
|
||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
# Type definition
|
# Julia has a type system.
|
||||||
|
# Every value has a type; variables do not have types themselves.
|
||||||
|
# You can use the `typeof` function to get the type of a value.
|
||||||
|
typeof(5) #=> Int64
|
||||||
|
|
||||||
|
# Types are first-class values
|
||||||
|
typeof(Int64) #=> DataType
|
||||||
|
typeof(DataType) #=> DataType
|
||||||
|
# DataType is the type that represents types, including itself.
|
||||||
|
|
||||||
|
# Types are used for documentation, optimizations, and dispatch.
|
||||||
|
# They are not statically checked.
|
||||||
|
|
||||||
|
# Users can define types
|
||||||
|
# They are like records or structs in other languages.
|
||||||
|
# New types are defined used the `type` keyword.
|
||||||
|
|
||||||
|
# type Name
|
||||||
|
# field::OptionalType
|
||||||
|
# ...
|
||||||
|
# end
|
||||||
type Tiger
|
type Tiger
|
||||||
taillength::Float64
|
taillength::Float64
|
||||||
coatcolor # no type annotation is implicitly Any
|
coatcolor # not including a type annotation is the same as `::Any`
|
||||||
end
|
end
|
||||||
# default constructor is the properties in order
|
|
||||||
# so, Tiger(taillength,coatcolor)
|
|
||||||
|
|
||||||
# Type instantiation
|
# The default constructor's arguments are the properties
|
||||||
tigger = Tiger(3.5,"orange") # the type doubles as the constructor function
|
# of the tyep, in order the order they are listed in the definition
|
||||||
|
tigger = Tiger(3.5,"orange") #=> Tiger(3.5,"orange")
|
||||||
|
|
||||||
# Abtract Types
|
# The type doubles as the constructor function for values of that type
|
||||||
|
sherekhan = typeof(tigger)(5.6,"fire") #=> Tiger(5.6,"fire")
|
||||||
|
|
||||||
|
# These struct-style types are called concrete types
|
||||||
|
# They can be instantiated, but cannot have subtypes.
|
||||||
|
# The other kind of types is abstract types.
|
||||||
|
|
||||||
|
# abstract Name
|
||||||
abstract Cat # just a name and point in the type hierarchy
|
abstract Cat # just a name and point in the type hierarchy
|
||||||
|
|
||||||
# * types defined with the type keyword are concrete types; they can be
|
# Abstract types cannot be instantiated, but can have subtypes.
|
||||||
# instantiated
|
# For example, Number is an abstract type
|
||||||
#
|
subtypes(Number) #=> 6-element Array{Any,1}:
|
||||||
# * types defined with the abstract keyword are abstract types; they can
|
# Complex{Float16}
|
||||||
# have subtypes.
|
# Complex{Float32}
|
||||||
#
|
# Complex{Float64}
|
||||||
# * each type has one supertype; a supertype can have zero or more subtypes.
|
# Complex{T<:Real}
|
||||||
|
# ImaginaryUnit
|
||||||
|
# Real
|
||||||
|
subtypes(Cat) #=> 0-element Array{Any,1}
|
||||||
|
|
||||||
|
# Every type has a super type; use the `super` function to get it.
|
||||||
|
typeof(5) #=> Int64
|
||||||
|
super(Int64) #=> Signed
|
||||||
|
super(Signed) #=> Real
|
||||||
|
super(Real) #=> Number
|
||||||
|
super(Number) #=> Any
|
||||||
|
super(super(Signed)) #=> Number
|
||||||
|
super(Any) #=> Any
|
||||||
|
# All of these type, except for Int64, are abstract.
|
||||||
|
|
||||||
|
# <: is the subtyping operator
|
||||||
type Lion <: Cat # Lion is a subtype of Cat
|
type Lion <: Cat # Lion is a subtype of Cat
|
||||||
mane_color
|
mane_color
|
||||||
roar::String
|
roar::String
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# You can define more constructors for your type
|
||||||
|
# Just define a function of the same name as the type
|
||||||
|
# and call an existing constructor to get a value of the correct type
|
||||||
|
Lion(roar::String) = Lion("green",roar)
|
||||||
|
# This is an outer constructor because it's outside the type definition
|
||||||
|
|
||||||
type Panther <: Cat # Panther is also a subtype of Cat
|
type Panther <: Cat # Panther is also a subtype of Cat
|
||||||
eye_color
|
eye_color
|
||||||
Panther() = new("green")
|
Panther() = new("green")
|
||||||
# Panthers will only have this constructor, and no default constructor.
|
# Panthers will only have this constructor, and no default constructor.
|
||||||
end
|
end
|
||||||
|
# Using inner constructors, like Panter does, gives you control
|
||||||
|
# over how values of the type can be created.
|
||||||
|
# When possible, you should use outer constructors rather than inner ones.
|
||||||
|
|
||||||
# Multiple Dispatch
|
####################################################
|
||||||
|
## 6. Multiple-Dispatch
|
||||||
|
####################################################
|
||||||
|
|
||||||
# In Julia, all named functions are generic functions
|
# In Julia, all named functions are generic functions
|
||||||
# This means that they are built up from many small methods
|
# This means that they are built up from many small methods
|
||||||
# For example, let's make a function meow:
|
# Each constructor for Lion is a method of the generic function Lion.
|
||||||
|
|
||||||
|
# For a non-constructor example, let's make a function meow:
|
||||||
|
|
||||||
|
# Definitions for Lion, Panther, Tiger
|
||||||
function meow(cat::Lion)
|
function meow(cat::Lion)
|
||||||
cat.roar # access properties using dot notation
|
cat.roar # access type properties using dot notation
|
||||||
end
|
end
|
||||||
|
|
||||||
function meow(cat::Panther)
|
function meow(cat::Panther)
|
||||||
@ -532,21 +587,76 @@ function meow(cat::Tiger)
|
|||||||
"rawwwr"
|
"rawwwr"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Testing the meow function
|
||||||
meow(tigger) #=> "rawwr"
|
meow(tigger) #=> "rawwr"
|
||||||
meow(Lion("brown","ROAAR")) #=> "ROAAR"
|
meow(Lion("brown","ROAAR")) #=> "ROAAR"
|
||||||
meow(Panther()) #=> "grrr"
|
meow(Panther()) #=> "grrr"
|
||||||
|
|
||||||
|
# Review the local type hierarchy
|
||||||
|
issubtype(Tiger,Cat) #=> false
|
||||||
|
issubtype(Lion,Cat) #=> true
|
||||||
|
issubtype(Panther,Cat) #=> true
|
||||||
|
|
||||||
|
# Defining a function that takes Cats
|
||||||
function pet_cat(cat::Cat)
|
function pet_cat(cat::Cat)
|
||||||
println("The cat says $(meow(cat))")
|
println("The cat says $(meow(cat))")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pet_cat(Lion("42")) #=> prints "The cat says 42"
|
||||||
try
|
try
|
||||||
pet_cat(tigger) #=> ERROR: no method pet_cat(Tiger,)
|
pet_cat(tigger) #=> ERROR: no method pet_cat(Tiger,)
|
||||||
catch e
|
catch e
|
||||||
println(e)
|
println(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
pet_cat(Lion(Panther(),"42")) #=> prints "The cat says 42"
|
# In OO languages, single dispatch is common;
|
||||||
|
# this means that the method is picked based on the type of the first argument.
|
||||||
|
# In Julia, all of the argument types contribute to selecting the best method.
|
||||||
|
|
||||||
|
# Let's define a function with more arguments, so we can see the difference
|
||||||
|
function fight(t::Tiger,c::Cat)
|
||||||
|
println("The $(t.coatcolor) tiger wins!")
|
||||||
|
end
|
||||||
|
#=> fight (generic function with 1 method)
|
||||||
|
|
||||||
|
fight(tigger,Panther()) #=> prints The orange tiger wins!
|
||||||
|
fight(tigger,Lion("ROAR")) #=> prints The orange tiger wins!
|
||||||
|
|
||||||
|
# Let's change the behavior when the Cat is specifically a Lion
|
||||||
|
fight(t::Tiger,l::Lion) = println("The $(l.mane_color)-maned lion wins!")
|
||||||
|
#=> fight (generic function with 2 methods)
|
||||||
|
|
||||||
|
fight(tigger,Panther()) #=> prints The orange tiger wins!
|
||||||
|
fight(tigger,Lion("ROAR")) #=> prints The green-maned lion wins!
|
||||||
|
|
||||||
|
# We don't need a Tiger in order to fight
|
||||||
|
fight(l::Lion,c::Cat) = println("The victorious cat says $(meow(c))")
|
||||||
|
end
|
||||||
|
#=> fight (generic function with 3 methods)
|
||||||
|
|
||||||
|
fight(Lion("balooga!"),Panther()) #=> prints The victorious cat says grrr
|
||||||
|
try
|
||||||
|
fight(Panther(),Lion("RAWR")) #=> ERROR: no method fight(Panther,Lion)
|
||||||
|
catch
|
||||||
|
end
|
||||||
|
|
||||||
|
# Also let the cat go first
|
||||||
|
fight(c::Cat,l::Lion) = println("The cat beats the Lion")
|
||||||
|
#=> Warning: New definition
|
||||||
|
# fight(Cat,Lion) at none:1
|
||||||
|
# is ambiguous with
|
||||||
|
# fight(Lion,Cat) at none:2.
|
||||||
|
# Make sure
|
||||||
|
# fight(Lion,Lion)
|
||||||
|
# is defined first.
|
||||||
|
#fight (generic function with 4 methods)
|
||||||
|
|
||||||
|
# This warning is because it's unclear which fight will be called in:
|
||||||
|
fight(Lion("RAR"),Lion("brown","rarrr")) #=> prints The victorious cat says rarrr
|
||||||
|
# The result may be different in other versions of Julia
|
||||||
|
|
||||||
|
fight(l::Lion,l2::Lion) = println("The lions come to a tie")
|
||||||
|
fight(Lion("RAR"),Lion("brown","rarrr")) #=> prints The lions come to a tie
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -554,3 +664,4 @@ pet_cat(Lion(Panther(),"42")) #=> prints "The cat says 42"
|
|||||||
|
|
||||||
You can get a lot more detail from [The Julia Manual](http://docs.julialang.org/en/latest/manual/)
|
You can get a lot more detail from [The Julia Manual](http://docs.julialang.org/en/latest/manual/)
|
||||||
|
|
||||||
|
The best place to get help with Julia is the (very friendly) [mailing list](https://groups.google.com/forum/#!forum/julia-users).
|
||||||
|
Loading…
Reference in New Issue
Block a user