Julialang:在抽象类型上强制接口

时间:2019-06-11 01:54:42

标签: julia

我一直在尝试了解Julialang的类型系统,但是某些设计方面仍然使我感到困惑。我希望有人能澄清一下。

因此,这里的问题是关于抽象类型及其具体实现。根据我的观点,understand Julia抽象类型对其具体实现没有任何约束。因此,无法保证适用于Abstract类型的方法将适用于该类型的具体实现。

我知道Julia不使用类或遵循继承。但是我只想避免在我的代码中生成各种错误。如果有不同的设计范例,那么有人可以回答下面的问题2。

所以我有2个问题。

  1. 这仍然是语言的工作方式吗?只是为了确认自博客发布以来没有任何变化。

  2. 用户如何围绕这个看似漏洞设计软件?

链接示例中的问题示例:

abstract type AbstractPerson end
abstract type AbstractStudent <: AbstractPerson end
abstract type AbstractTeacher <: AbstractPerson end

struct Person <: AbstractPerson
  name::String    
end

struct Student <: AbstractStudent
  name::String  
  grade::Int
  hobby::String
end

struct MusicStudent <: AbstractStudent
  grade::Int
end

现在,如果我在抽象类型上创建一些方法。

get_name(x::AbstractPerson) = x.name
p1 = Person("elroy")
get_name(p1)

>"elroy"

因此,即使MusicStudentAbstractPerson的子类型,MusicStudent也没有name属性。这意味着可以观察到以下行为。

m1 = MusicStudent(10)
get_name(m1)


ERROR: type MusicStudent has no field name

Stacktrace:
 [1] getproperty(::Any, ::Symbol) at ./sysimg.jl:18
 [2] get_name(::MusicStudent) at ./In[2]:1
 [3] top-level scope at In[13]:2

所以这里的问题是Julia允许我使用实质上不完整的构造函数实例化类型变量m1。而且,当我尝试运行该功能时,只会给我一个错误。

因此,这意味着如果我为Abstract Type编写函数,则不能保证该Type的每个具体实现都具有相同的接口。这似乎将使代码变得非常脆弱,因为开发人员将不知道哪种类型实现哪些属性和方法。

2 个答案:

答案 0 :(得分:2)

这种行为难道不是在实施Persons时的一个错误吗?如果您确实希望行为无一例外地发生,则可以定义一个默认方法:

julia> get_name(p::AbstractPerson) = try return p.name catch y return "" end
get_name (generic function with 1 method)

julia> m1 = MusicStudent(10)
MusicStudent(10)

julia> get_name(m1)
""

我认为潜在的难题可能是,在Julia中,您不能继承称为“名称”的数据字段作为对象层次结构的一部分。这里有一个关于这个真正问题的很好的讨论(请参阅@forward宏的提及):

https://discourse.julialang.org/t/composition-and-inheritance-the-julian-way/11231

答案 1 :(得分:1)

基本答案是,在julia中,方法的接口被认为是定义为采用该类型元素的方法。例如,AbstractArray指定实现应实现getIndexsize。不使字段成为接口的一部分的原因是,不这样做会使内存效率更高的代码,因为每种类型都可以以最明智的方式定义方法。例如,如果我想创建一个名为Bob的类型,该类型是所有名为bob的人的子类型,则我不想每次都存储他的名字。通过使用方法,Julia可以以意想不到的方式为将来的扩展提供更多的潜力。

从技术上讲,这种方法失去了“安全性”,但唯一的方法是如果使用不存在的字段编写代码,在这种情况下会出现错误。这种安全性没什么用,因为它只会给您带来编译错误,从而减慢开发速度。