I read in a book that "you can't create traditional 'classes' in julia with single-dispatch-style methods like obj.myfunc()
" ... and I thought that sounded more like a challenge than a fact.
So here's my JavaClass
type with public / private fields and methods just for the sheer shock and horror factor of having something ugly like this in Julia, after all the trouble the devs have gone to to avoid it:
type JavaClass
# Public fields
name::String
# Public methods
getName::Function
setName::Function
getX::Function
getY::Function
setX::Function
setY::Function
# Primary Constructor - "through Whom all things were made."
function JavaClass(namearg::String, xarg::Int64, yarg::Int64)
# Private fields - implemented as "closed" variables
x = xarg
y = yarg
# Private methods used for "overloading"
setY(yarg::Int64) = (y = yarg; return nothing)
setY(yarg::Float64) = (y = Int64(yarg * 1000); return nothing)
# Construct object
this = new()
this.name = namearg
this.getName = () -> this.name
this.setName = (name::String) -> (this.name = name; return nothing)
this.getX = () -> x
this.getY = () -> y
this.setX = (xarg::Int64) -> (x = xarg; return nothing)
this.setY = (yarg) -> setY(yarg) #Select appropriate overloaded method
# Return constructed object
return this
end
# a secondary (inner) constructor
JavaClass(namearg::String) = JavaClass(namearg, 0,0)
end
Example use:
julia> a = JavaClass("John", 10, 20);
julia> a.name # public
"John"
julia> a.name = "Jim";
julia> a.getName()
"Jim"
julia> a.setName("Jack")
julia> a.getName()
"Jack"
julia> a.x # private, cannot access
ERROR: type JavaClass has no field x
julia> a.getX()
10
julia> a.setX(11)
julia> a.getX()
11
julia> a.setY(2) # "single-dispatch" call to Int overloaded method
julia> a.getY()
2
julia> a.setY(2.0)
julia> a.getY() # "single-dispatch" call to Float overloaded method
2000
julia> b = JavaClass("Jill"); # secondary constructor
julia> b.getX()
0
Essentially, the constructor becomes a closure, which is how one creates "private" fields and methods / overloading.
Any thoughts? (other than "OMG Why??? Why would you do this??")
Any other approaches?
Any scenarios you could envisage where this might fail spectacularly?
While of course this isn't the idiomatic way to create objects and methods in julia, there's nothing horribly wrong with it either. In any language with closures you can define your own "object systems" like this, for example see the many object systems that have been developed within Scheme.
In julia v0.5 there is an especially slick way to do this due to the fact that closures represent their captured variables as object fields automatically. For example:
julia> function Person(name, age)
getName() = name
getAge() = age
getOlder() = (age+=1)
()->(getName;getAge;getOlder)
end
Person (generic function with 1 method)
julia> o = Person("bob", 26)
(::#3) (generic function with 1 method)
julia> o.getName()
"bob"
julia> o.getAge()
26
julia> o.getOlder()
27
julia> o.getAge()
27
It's weird that you have to return a function to do this, but there it is. This benefits from many optimizations like the language figuring out precise field types for you, so in some cases we can even inline these "method calls". Another cool feature is that the bottom line of the function controls which fields are "public"; anything listed there will become a field of the object. In this case you get only the methods, and not the name and age variables. But if you added name
to the list then you'd be able to do o.name
as well. And of course the methods are also multi-methods; you can add multiple definitions for getOlder
etc. and it will work like you expect.
来源:https://stackoverflow.com/questions/39133424/how-to-create-a-single-dispatch-object-oriented-class-in-julia-that-behaves-l