如何创建“单一分发,面向对象的类"?在julia中,行为类似于具有公共/私有字段和方法的标准Java类 [英] How to create a "single dispatch, object-oriented Class" in julia that behaves like a standard Java Class with public / private fields and methods

查看:165
本文介绍了如何创建“单一分发,面向对象的类"?在julia中,行为类似于具有公共/私有字段和方法的标准Java类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在书中读到您不能使用obj.myfunc()之类的单派发式方法在julia中创建传统的'类'",我认为这听起来像是挑战,而不是事实. /p>

所以这是我的JavaClass类型,带有公共/私有字段和方法,只是为了在朱莉娅身上拥有像这样丑陋的东西而感到震惊和恐怖,毕竟开发人员已经避免了这种麻烦:

 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
 

示例用法:

 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
 

本质上,构造函数成为一个闭包,这就是创建私有"字段和方法/重载的方式. 有什么想法吗? (除了"OMG为什么?为什么要这么做?" )
还有其他方法吗?
您可以设想任何方案在哪里可能会失败吗?

解决方案

虽然这不是在julia中创建对象和方法的惯用方式,但也没有任何可怕的错误.在任何带有闭包的语言中,您都可以像这样定义自己的对象系统",例如,查看Scheme中开发的许多对象系统.

在julia v0.5中,由于闭包自动将其捕获的变量表示为对象字段,因此存在一种特别巧妙的方法.例如:

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

很奇怪,您必须返回一个函数来执行此操作,但是确实如此.这得益于许多优化,例如语言为您确定了精确的字段类型,因此在某些情况下,我们甚至可以内联这些方法调用".另一个很酷的功能是该函数的底行控制哪些字段是公共"的;在那里列出的所有内容都将成为对象的字段.在这种情况下,您只会获得方法,而不会获得名称和年龄变量.但是,如果将name添加到列表中,则也可以执行o.name.当然,这些方法也是多种方法.您可以为getOlder等添加多个定义,它将按预期运行.

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.

这篇关于如何创建“单一分发,面向对象的类"?在julia中,行为类似于具有公共/私有字段和方法的标准Java类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆