是否仍然需要特定类型?


20

前几天发生在我身上的一件事是仍然需要特定类型的东西或使我们退缩的遗留物。我的意思是:我们真的需要short,int,long,bigint等吗?

我了解原因,变量/对象保留在内存中,需要分配内存,因此我们需要知道变量的大小。但是,实际上,现代编程语言不应该能够处理“自适应类型”,即,如果仅在shortint范围内分配了某些内容,则它使用较少的字节,并且如果某个内容突然分配了非常大的数量,则将分配内存符合特定情况。

浮点数,实数和双精度数有点棘手,因为类型取决于您需要的精度。但是,在大多数情况下(在.Net中),字符串通常应能够占用较少的内存,而在大多数情况下,使用ascii,但是由于unicode编码,字符串总是占用两倍的内存。

特定类型的一个论点可能是它是规范的一部分,例如,变量不应大于某个值,因此我们将其设置为shortint。但是为什么没有类型约束呢?能够为变量(和属性)设置允许的范围和值将更加灵活和强大。

我意识到改造类型体系结构存在巨大问题,因为它与底层硬件紧密集成,并且序列化之类的事情确实变得棘手。但是从编程角度来看,应该很棒吗?


6
PHP,Ruby,Perl和其他工具不需要您声明变量的类型。环境为您解决了这一问题。
FrustratedWithFormsDesigner

7
Unicode字符串恰好仅用于ASCII(UTF-8)时,不必占用额外的内存。

2
但是IMO的变体类型和自适应类型之间是有区别的。变体根本不会输入,但是在分配时会被输入,而自适应类型将被输入,但更为宽松。(我喜欢类型约束的概念)
Homde 2011年

这让我想起了这个项目:tom.lokhorst.eu/media/…–
LennyProgrammers

4
那艾达呢?type hour is range 0 .. 23;
mouviciel 2011年

Answers:


12

我完全相信情况会如此。语义约束比实现约束更有价值。担心对象的大小就像感觉到面向对象编程即将来临时的速度。

它并没有取代性能关键的程序。它只是使非性能关键型编程更具生产力。


1
在.NET 4.0中签出代码合同
Steven Jeuris 2011年

+1当涉及到数据存储/传输(例如网络)时,约束是最大化协议/实现效率的基础。此外,如果可以使用类型化的集合,则可以有很多基础。除此之外,可以肯定地认为效率会倒退(特别是如果它降低了语义错误的可能性)。
伊万·普赖斯

9

适应性类型意味着进行适应的逻辑,意味着在运行时运行该逻辑(模板化和编译时需要特定的类型,类型推断是在两种情况下都能发挥最大作用的特例)。在性能不是很关键且系统尺寸合理的环境中,可以进行额外的工作。在其他环境中则不是(嵌入式系统是一种,在某些情况下,您有时必须使用32/64位整数类型才能实现cpu性能,而必须使用8/16位整数类型来实现静态内存备份优化)。

甚至支持后期绑定(在运行时解析类型,如VB6)的通用语言也往往会促进立即强类型化(VB.NET),这是因为滥用后期绑定时会出现性能下降的情况,而且您经常当类型不是显式的时,最终会得到难看的代码(Visual Basic中的参考/专业重构-Danijel Arsenovski)。


请定义“自动键入”。

@delnan:我用的是用后期绑定来代替自动键入:)
Matthieu

有很多通用语言可以在运行时解析类型,Common Lisp仅举一种。(出于性能目的,您可以在Common Lisp中声明类型,因此只能在对性能有严格要求的部分中声明类型。)
David Thornley

@David Thornley:“强制”强类型输入可能太强了,“促进”会更合适,请相应地更新我的答案。允许您根据情况在两种绑定之间进行选择的语言肯定比以一种或另一种方式强制使用的语言更好。尤其是在不进行低级编程并专注于逻辑时。
Matthieu

4

简单性,内存和速度 当我声明一个变量时,该变量的内存在一个块中分配。为了支持动态增长的变量,我将不得不在该变量中添加非连续内存的概念(要么保留该变量,要么保留该变量可以代表的最大块)。非连续内存会降低分配/检索的性能。在我只需要一个字节但系统保留很长时间的情况下,分配最大的可能是浪费的。

考虑一下数组和向量(或链表)之间的权衡。对于数组,查找特定位置是获得起始位置并移动内存指针x空间以在内存中定位该新位置的简单问题。将一个int视为bit [32],读取一个int涉及遍历该数组以获取所有位值。

要创建动态数字类型,您必须将其从位数组更改为位向量。读取动态编号涉及到头部,获取该位,询问内存中的下一个位,移至该位置,获取该位等。对于动态编号中的每一位,您都需要执行以下三个操作:当前),读取(下一个地址),移动(下一个)。想象一下,读取一百万个数字的值。那是一百万额外的操作。这似乎微不足道。但是请考虑每毫秒都很重要的系统(例如财务系统)。

做出的决定是,与影响系统性能相比,开发人员有责任检查大小并进行验证。


1
另一种选择是实现类似于arraylists的数字,当数字超过当前大小时,将重新分配数组。另外,您还必须考虑用户希望溢出循环的情况。
迈克尔·布朗

没错,但是有点简化。您可能会想出一个更有效的数组结构,而在大多数情况下,速度不如静态类型的“足够快”。例如,您可以将信息保存在不同类型的块上,如果阵列不是完全锯齿状的,则不会占用更多的内存或性能。否则数组可能会牺牲一些内存来拥有某种索引。该阵列甚至可以根据其内容进行自我优化。如果需要性能,您仍然可以选择通过类型约束键入memorysize。
洪德堡

公平地说,它并不像您看到的那样残酷。cf我即将来临的答案。
保罗·内森

3

以硬件为中心的语言和项目需要特定的类型。一个示例是在线网络协议。

但是,让我们以一种有趣的方式,使用C ++之类的语言来创建varint类型。从newint数组构建它。

实施加法并不难:只需将字节异或并检查高位:如果有进位运算,则new在新的高位字节中将位转过来。减法在2的补码表示形式中微不足道。(这也称为波纹进位加法器)。

乘法也类似。使用迭代加法/移位。和往常一样,尾巴上真正的扭曲是分度[*]。

但是,发生这种情况时您失去了什么?

  • 确定性时间。您有一个syscall(new),它可能在不一定可控的点处触发。

  • 确定性空间。

  • 半软件数学很慢。

如果您需要使用硬件层语言,还需要在高温(慢)水平操作,并且希望嵌入脚本引擎,varint使得有很大的意义。它可能写在某个地方。

[*] cf硬件数学算法可实现更快的方式-通常,诀窍是并行操作。


2

这是一个很好的问题。它解释了为什么像Python这样的语言不需要“ short,int,long,bigint等”:整数就是整数(Python 3中只有一个整数类型),并且没有限制大小(超出了限制)。当然,计算机的内存)。

至于Unicode,UTF-8编码(Unicode的一部分)仅对ASCII字符使用单个字符,因此还不错。

更一般而言,动态语言似乎朝您提到的方向发展。但是,出于效率原因,在某些情况下(例如必须快速运行的程序),更多受约束的类型很有用。在可预见的将来,由于处理器以字节(或2、4、8等字节)组织数据,因此我看不出有太大变化。


1

以语言理论为基础,您是对的。类型应基于一组合法状态,这些状态可用的转换以及在这些状态上可执行的操作。

但是,这通常是OOP编程以其典型形式提供的功能。实际上,在Java中,您实际上是在谈论BigIntegerand BigDecimal类,它们根据存储对象所需的空间来分配空间。(正如FrustratedWithFormsDesigner指出的那样,许多脚本类型的语言在这方面走得更远,甚至不需要声明类型,就可以存储您提供的任何内容。)

但是,性能仍然是相关的,并且由于在运行时切换类型的成本很高,并且由于编译器无法保证编译时变量的最大大小,因此对于许多语言中的简单类型,我们仍然具有静态大小的变量。


我意识到,某种动态/自适应类型的输入似乎比我们现在拥有的成本高且性能低,并且使用当前的编译器肯定会做到。但是我们是否100%确信,如果您从头开始构建一种语言和编译器,就不能使它们(甚至不如静态类型的语言)那么快,至少值得这样做。
霍姆德

1
@MKO:为什么不试试看?
Anon。

1
是的,您可以使其变得切实可行(但可能永远不会像静态数字系统那样快)。但是“值得”部分比较棘手。大多数人使用的数据的范围恰好适合于intdouble,如果不适合,他们会意识到这一点,因此动态值大小调整是他们不需要付费的功能。
jprete 2011年

作为所有程序员,我当然梦想有一天自己写自己的语言;)
Homde 2011年

@jprete:我不同意;大多数人不知道可能会有较大的中间结果。这样的语言可以并且已经足够快地用于大多数目的。
David Thornley

1

这取决于语言。对于Python,Ruby,Erlang等高级语言,您仅具有整数和十进制数字的概念。

但是,对于某些类别的语言而言,具有这些类型非常重要。当您编写用于读取和写入二进制格式(例如PNG,JPeg等)的代码时,您需要准确地知道一次要读取多少信息。与编写操作系统内核和设备驱动程序相同。并非每个人都这样做,并且在高级语言中,他们使用C库进行详细的繁重工作。

在中short,还有一些地方可以容纳更具体的类型,但是许多开发问题并不需要那么精确。


0

我最近创建了一个梯形逻辑编辑器和运行时,并决定在类型方面受限制:

  • 布尔型
  • 约会时间

我相信它使用户更直观。这与大多数PLC有着根本性的区别,大多数PLC具有您在C之类的语言中看到的所有“正常”类型范围。


0

编程语言一直朝着这个方向发展。以字符串为例。在老的语言,你必须声明的字符串的大小,就像PIC X(42)在COBOL,DIM A$(42)在基本的一些版本,或[ VAR] CHAR(42)在SQL。在现代语言中,您只有一种动态分配的string类型,不需要考虑大小。

整数不同,但是:

我的意思是:我们真的需要short,int,long,bigint等吗?

看一下Python。它用于区分机器大小(int)和任意大小(long)的整数。在3.x中,前一个已消失(旧long是新的int),没有人会错过。

但是对于和形式的8位整数序列仍然有一种特殊的类型。为什么不分别使用a 或整数?是的,确实有多余的类似字符串的方法,但是效率肯定与它有很大关系。bytesbytearraytuplelistbytestuple

浮点数,实数和双精度数有点棘手,因为类型取决于您需要的精度。

并不是的。“一切都是双精度的”方法非常普遍。


1
也许基本类型应该声明该类型的基本意图,即int表示“普通”数字,double表示所有普通的“ decimals”(为简单起见,int不能为小数吗?)“ money”使用数量和字节用于处理二进制数据。通过属性声明的类型约束可以允许声明允许范围,十进制精度,可空性甚至允许值。如果您可以通过这种方式创建自定义和可重用的类型,
那就太好了

@konrad:恕我直言,“无符号”整数在C语言中引起如此麻烦的原因是它们有时用于表示数字,有时用于表示环绕的抽象代数环的成员。具有单独的“ ring”和“ unsigned number”类型可以确保类似的代码unum64 += ring32a-ring32b将始终产生正确的行为,而不管默认整数类型是16位还是64位[请注意,+=必不可少的使用;像这样的表达unum64a = unum64b + (ring32a-ring32b);应该被拒绝为模棱两可。]
supercat

0

我了解原因,变量/对象保留在内存中,需要分配内存,因此我们需要知道变量的大小。但是,实际上,现代编程语言不应该能够处理“自适应类型”,即,如果仅在shortint范围内分配了某些内容,则它使用较少的字节,并且如果某个内容突然分配了非常大的数量,则将分配内存符合特定情况。

浮点数,实数和双精度数有点棘手,因为类型取决于您需要的精度。但是,在大多数情况下(在.Net中),字符串通常应能够占用较少的内存,而在大多数情况下,使用ascii,但是由于unicode编码,字符串总是占用两倍的内存。

Fortran也有类似的情况(我不知道这是否正是您的意思,因为我确实看到了两个问题)。例如,在F90以上版本中,无需显式定义type size。这很好,不仅因为它使您可以集中定义数据类型,而且还提供了一种可移植的方式来定义它们。在所有处理器上的所有实现中,REAL * 4都不相同(按处理器,我的意思是CPU +编译器),不是一针见血。

selected_real_kind(p,r)返回实数数据类型的种类值,其十进制精度至少为p个数字,并且指数范围至少为r。

例如,你走了;

program real_kinds
integer,parameter :: p6 = selected_real_kind(6)
integer,parameter :: p10r100 = selected_real_kind(10,100) !p is precision, r is range
integer,parameter :: r400 = selected_real_kind(r=400)
real(kind=p6) :: x
real(kind=p10r100) :: y
real(kind=r400) :: z

print *, precision(x), range(x)
print *, precision(y), range(y)
print *, precision(z), range(z)
end program real_kinds

(我认为这是一个不言自明的例子)。

仍然不知道我是否正确理解了您的问题,这就是您所提到的。

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.