OOP语言和类型的类


9

在编程语言理论中,类型是一组值。例如,类型“ int”是所有整数值的集合。

在OOP语言中,类是类型,是吗?

当一个类定义了一个以上的成员时,例如

class myclass{
    int a; 
    double b;
}

当我们谈论课程时,我们的意思是

  • (a,b)哪里a是一个整数,并且b是一个双精度数”,或者
  • “ { (x,y)| x是整数,y是双精度}”吗?

实例myclass是什么意思?

  • (a,b)哪里a是一个整数,并且b是一个双精度数”,或者
  • 一个对象,该对象占用一个内存空间,并且可以(不一定是空)可以存储对象(x,y)xint 在哪里,ydouble在哪里?

2
类是一种类型。“ {{x,y)| x是任何int,y是任何double}”几乎是正确的,除了两件事:1)在概念上讲,一个类是一个记录时,您使用过一个元组-您引用它按名称,而不是位置的字段; 2)不是每个同场的记录a,并b有该类型的成员,基利安第四提到MYCLASS是,同构,以记录与领域ab类型int以及double-你可以采取记录一样,并把它变成的一个实例myclass
Doval

1
在强类型语言中,类是类型。在弱类型语言中,它可能是也可能不是类型。
shawnhcorey 2015年

1
在编程语言理论中,类型是一组值吗?我认为您需要给自己买另一本书或其他老师,或两者兼具。“变量”或“常量”具有“类型”,通常具有“值”。有零值类型,标量和复合值类型,其中变量或常量的值包含子变量/子常量。
user1703394

1
@ user1703394类型一组值。32位整数类型是2 ^ 32个不同值的集合。如果表达式的计算结果为该类型的值,则说明该值在该集合中。数学运算符只是对该集合的值的函数。
2015年

1
我也将审慎地将类型视为值集。集具有不严格适用于类型的关系。对于概念化类型,这是一个很好的模型,但是一旦您开始更仔细地研究事物,它就会崩溃-当引入子类型化时,它甚至会崩溃。
Telastyn

Answers:


30

都不行

我想你是在问,拥有相同的字段类型集是否足以将其归类为同一类,或者是否也必须命名相同。答案是:“即使没有相同的类型名称也足够!” 结构上等效的类不一定是类型兼容的。

例如,如果您有一个CartesianCoordinates和一个PolarCordinates类,它们可能都具有两个数字作为其字段,它们甚至可能具有相同的Number类型和相同的名称,但是它们仍然不兼容,并且的实例PolarCoordinates也不会是的实例CartesianCoordinates。根据其预期用途而不是其当前实现来区分类型的能力是编写更安全,更可维护的代码的非常有用的一部分。


9
应当指出,在某些语言中,结构上等效足以使一种类型成为另一种类型的子类型(并且反之亦然)。虽然那绝对不常见/不受欢迎。
Telastyn

7
@Tim typedef不会创建类型,而是将用于引用现有类型的名称作为别名。
2015年

1
@DevSolar他明确提到了C,除了C ++,我不知道使用该关键字的任何其他语言。
2015年

3
@Telastyn-这些语言应该用火杀死。
乔恩·斯托利

4
@JonStory结构子类型在模块级别很有用;interface如果您想进行单元测试,那么它的不足迫使您将所有内容都转换为Java和C#。您最终只写了很多样板文件,即使您无意在运行时更改它,也可以更改程序将使用的特定类。
2015年

6

类型没有设置。

您会发现,集合论具有许多根本不适用于类型的特征,反之亦然。例如,一个对象具有单一规范类型。它可能是几种不同类型的实例,但是仅使用这些类型中的一种来实例化它。集合论没有“规范”集合的概念。

如果您有描述子集内容的规则,则集合论可让您即时创建子集。类型理论通常不允许这样做。虽然大多数语言有Number型或类似的东西,他们具备的EvenNumber类型,也不是简单的创建一个。我的意思是,定义类型本身很容易,但是任何现有Number的甚至碰巧都不会神奇地转换为EvenNumbers的。

实际上,说“可以创建”子集有点不诚实,因为集合完全是另一种动物。在集合论中,这些子集已经存在,可以定义它们的所有无限方式。在类型理论中,我们通常期望在任何给定时间处理有限数量(如果很大)的类型。据说存在的唯一类型是我们实际上定义的类型,而不是我们可能定义的每种类型。

不允许直接或间接包含它们自己。某些语言(例如Python)提供的类型的规则结构较少(在Python中,type规范类型为typeobject被视为的实例object)。另一方面,大多数语言都不允许用户定义的类型进行这种欺骗。

通常允许集合相互重叠而不相互包含。这在类型理论中并不常见,尽管某些语言确实以多重继承的形式支持它。其他语言(例如Java)仅允许对此形式进行限制或完全禁止。

存在空类型(称为底部类型),但是大多数语言不支持它,或者不将其视为一流类型。与集合理论不同,“包含所有其他类型的类型”也存在(被称为top类型)并得到广泛支持。

注意:正如一些评论者先前指出的(在将话题转移到聊天之前),可以使用集合论和其他标准数学构造对类型进行建模。例如,您可以将类型成员资格建模为关系,而不是将类型建模为集合。但是实际上,如果使用类别理论而不是集合理论,则这要简单得多。例如,这就是Haskell如何建模其类型理论。


“子类型化”的概念实际上与“子集”的概念完全不同。如果X是的子类型Y,则意味着我们可以用的实例替换Y实例,X并且该程序在某种意义上仍将“起作用”。这是行为的,而不是结构的,尽管为了方便起见,某些语言(例如Go,Rust,可以说C)选择了后者,无论是对程序员还是对语言实现。


评论不作进一步讨论;此对话已转移至聊天
世界工程师

4

代数数据类型是讨论此问题的方法。

可以使用三种基本方式组合类型:

  • 产品。这基本上就是您所想的:

    struct IntXDouble{
      int a; 
      double b;
    }
    

    是产品类型;它的值是1 int和1的所有可能组合(即元组)double。如果您将数字类型视为集合,则产品类型的基数实际上就是字段基数的乘积。

  • 和。在过程语言中,直接表达有点尴尬(通常是使用带标记的并集来完成的),因此为了更好地理解,这是Haskell中的求和类型:

    data IntOrDouble = AnInt Int
                     | ADouble Double
    

    此类型的值的形式为AnInt 345ADouble 4.23,但始终只涉及一个数字(与产品类型不同,每个值都有两个数字)。因此,基数:首先枚举所有Int值,每个值都必须与AnInt构造函数结合在一起。另外,所有Double值都与组合在一起ADouble。因此求和类型

  • 求幂1。我将不在这里详细讨论,因为它根本没有明确的OO对应关系。

那类呢?我故意使用关键字struct而不是classfor IntXDouble。问题是,作为类型的类实际上没有通过其字段来表征,而这些字段仅仅是实现细节。关键因素是,班级可以拥有哪些可区别的价值。

什么相关的,虽然是一个类的值可以是的任何它的子类的!因此,一个类实际上是一个求和类型,而不是乘积类型:如果AB都是从中派生的myClass,则myClass本质上将是和的AB。不管实际执行什么。


1 这是函数(在数学意义上!);函数类型Int -> Double由指数表示DoubleInt。糟糕的是,如果您的语言没有适当的功能...


2
抱歉,但是我认为这是一个很差的答案。函数确实具有清晰的OO类似物,即方法(和单方法接口类型)。对象的基本定义是它既具有状态(字段/数据成员)又具有行为(方法/成员函数);您的答案忽略了后者。
ruakh 2015年

@ruakh:不。您当然可以在OO中实现函数,但是通常,方法不是函数(因为它们会修改状态等)。就此而言,过程语言中的“功能”也不是功能。确实,单静态方法接口最接近函数/指数类型,但是我希望避免对此进行讨论,因为它与该问题无关。
左转

...更重要的是,我的anwer 确实考虑了行为。确实,行为通常是您使用继承的原因,并且不同可能行为的统一准确地捕获了OO类的sum-type方面。
左转

@ruakh方法离不开它的对象。最接近的模拟static方法是方法,除了它们仍然不是一流的值。关于大多数OO语言的事情是,它们将对象作为最小的构建块,因此,如果您想要较小的对象,则必须使用对象来伪造它,并且最终仍然会拖入一堆本不应该具有的语义函数。例如,比较功能是否相等没有意义,但是您仍然可以比较两个伪功能对象。
2015年

@Doval 1)您可以在AFAIK周围传递方法,因此它们是一等值;2)比较功能是否相等确实很有意义,JS人员一直都这样做。

2

抱歉,但我不了解“原始”理论。我只能提供一种实用的方法。我希望这对于程序员来说是可以接受的。我对这里的礼节不熟悉。


OOP的中心主题是信息隐藏。确切地讲,类的数据成员对其客户不感兴趣。客户端发送消息实例(调用方法/成员函数),该消息可能会或可能不会修改内部状态。这个想法是,类的内部可能会更改,而客户端不会受到其影响。

对此的佐证是,该类负责确保其内部表示保持“有效”。假设一个类以两个整数存储(简化的)电话号码:

    int areacode;
    int number;

这些是类的数据成员。但是,课程可能会更多不仅仅是它的数据成员,它肯定不是定义为“一套INT X INT所有可能的值”。您不应该直接访问数据成员。

实例的构造可能会拒绝任何负数。也许该构造还可以以某种方式规范区号,甚至验证整个号码。因此,您最终将更接近您的"(a,b) where a is an int and b is a double",因为肯定不是该类中存储了任何两个int。

但是,就班级而言,这并不重要。定义该类的既不是数据成员的类型,也不是它们的可能值的范围,而是为它定义的方法

只要这些方法保持相同,实现者就可以将数据类型更改为浮点数,BIGNUM,字符串等,并且出于所有实际目的,它仍将是同一类


有一些设计模式可以确保内部表示的这种更改可以在客户端甚至没有意识到的情况下进行(例如,C ++中的pimpl习惯用法,它将任何数据成员隐藏在不透明的指针后面)。


1
It is neither the type of the data members, nor the range of their possible values that defines the class, it's the methods that are defined for it.数据成员仅在隐藏它们时才定义类。这可能是最常见的情况,但是不能肯定地说所有类都是如此。如果只有一个字段是公共的,则与其方法同样重要。
2015年

1
除非您使用Java进行编码,否则您别无选择,甚至您的愚蠢的无行为伪记录也必须是classes。(标记它们final可以帮助您理解要点,但仍然可以)。protected但是,成员仍然存在问题,成员可以继承,因此成为第二个用于子类实现者的API的一部分。
2015年

1
@Doval:我理解这是一个“理论”问题,这就是为什么我尽可能避免实际的语言问题。(就像我protected尽量不使用Java 一样,并且在实践中也尽可能。;
DevSolar 2015年

3
问题在于a class是一种依赖于语言的构造。据我所知,没有class类型论这样的东西。
2015年

1
@Doval:这是否意味着类型理论本身不适用于类,因为它们是超出该理论范围的构造?
DevSolar 2015年

2
  • 类型是一个类的描述/值范围,化合物的结构,或你有什么。OOPwise,它类似于“接口”。(从语言不可知的意义上讲。不是特定于语言的意思。例如,在Java中,int它是type,但与。无关interface。公共/受保护的字段规范也不是interface,但一个“接口”或部分类型。)

    要点是,它比具体定义更多的是语义定义。由于暴露的领域/行为及其定义的目的是一致的,因此仅构成因素。如果您没有两者,则没有类型兼容性。

  • 是实现一种类型的。它是一个模板,实际上定义了内部结构,附加的行为等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.