语言真的依赖于图书馆吗?

时间:2013-05-07 18:50:16

标签: c# programming-languages dependencies libraries

我一直想知道如何从编程语言到其库来管理依赖项。以C#为例。当我开始学习计算时,我会假设(错误地证明)语言本身是独立于最终可用于它的类库而设计的。也就是说,首先定义一组语言关键字(例如forclassthrow)加上语法和语义,并且可以从语言中使用的库是单独开发的。我曾经认为,这些库中的特定类不应该对语言的设计产生任何影响。

但这不起作用,或者不是一直都行不通。考虑throw。 C#编译器确保throw后面的表达式解析为异常类型。 Exception是库中的一个类,因此它根本不应该是特殊的。除了C#编译器为其指定特殊语义之外,它将与其他任何类一样。这是非常好的,但我的结论是语言的设计确实取决于类库中特定元素的存在和行为。

此外,我想知道如何管理这种依赖。如果我要设计一种新的编程语言,我会用什么技术将throw的语义映射到Exception这个非常特殊的类?

所以我的问题是两个:

  • 我认为语言设计与其基类库紧密耦合是否正确?
  • 如何在编译器和运行时内管理这些依赖项?使用了什么技术?

谢谢。

EDIT。感谢那些指出我的第二个问题非常含糊的人。我同意。我想要学习的是编译器存储的所需类型的引用。例如,它是否通过某种唯一ID找到类型?发布新版本的编译器或类库时会发生什么?我知道这仍然很模糊,我不期待一个精确的单段答案;相反,非常欢迎指向文学或博客文章。

4 个答案:

答案 0 :(得分:11)

  

我想学习的是编译器存储的所需类型的引用。例如,它是否通过某种唯一ID找到类型?

显然,C#编译器在源代码和元数据中维护一个可用的所有类型的内部数据库;这就是为什么编译器被称为“编译器” - 它编译关于源和库的数据集合

当C#编译器需要检查抛出的表达式是从System.Exception派生还是完全相同时,它假装在System上进行全局命名空间查找,然后执行查找Exception,找到该类,然后将得到的类信息与为表达式推导出的类型进行比较。

编译器团队使用这种技术,因为无论我们是编译源代码还是System.Exception都在元数据中,或者我们正在编译mscorlib本身并且System.Exception在源代码中,它就会起作用。

当然,作为一种性能优化,编译器实际上有一个“已知类型”列表,并提前填充该列表,这样它就不必每次都要花费大量的资源进行查询。您可以想象,您必须查找内置类型的次数是非常大。填充列表后,可以从列表中读取System.Exception的类型信息,而无需进行查找。

  

发布新版本的编译器或类库时会发生什么?

发生的事情是:一大堆开发人员,测试人员,经理,设计人员,编写人员和教育工作者聚在一起,花费数百万工时,确保编译器和类库在发布之前都能正常工作。

这个问题再次变得模糊不清。新的编译器发布会发生什么? 很多工作,这就是必须发生的事情。

  

我知道这仍然很模糊,我不希望有一个精确的单段答案;相反,非常欢迎指向文学或博客文章。

我写了一篇博客,其中包括C#语言及其编译器的设计。它位于http://ericlippert.com

答案 1 :(得分:5)

  

我会假设(可能是错误的)语言本身是独立于最终可用的类库而设计的。

在C#的情况下,你的假设是完全错误的。 C#1.0,​​CLR 1.0和.NET Framework 1.0都是一起设计的。随着语言,运行时和框架的发展,每个人的设计人员密切合作,以确保分配正确的资源,以便每个人都能按时发布新功能。

我不明白你完全错误的假设来自哪里;这听起来像是编写高级语言的低效方式,也是错过最后期限的好方法。

我可以看到编写像C这样的语言,这对于汇编程序来说基本上是一种更令人愉快的语法,没有库。但是,如果没有那个人和你一起在房间里设计async-await,你会怎么写呢Task<T>?这似乎是一种令人沮丧的运动。

  

我认为语言设计与其基类库紧密耦合是否正确?

在C#的情况下,是的,绝对的。为了正常工作,C#语言假定有许多类型可用且记录在案。

我曾经和一个开发人员度过了一个非常令人沮丧的时刻,他在使用foreach循环时遇到了一些完全疯狂的问题,然后才发现他已经编写了自己的IEnumerable<T>,其方法与真实的IEnumerable<T>略有不同{1}} 的。解决他的问题:不要这样做。

  

如何在编译器和运行时内管理这些依赖项?

我不知道如何开始回答这个不可思议的模糊问题。

答案 2 :(得分:3)

所有(实用)编程语言都具有最少数量的所需功能。对于现代“OO”语言,这还包括最少数量的所需类型。

如果Language Specification 中的类型是必需的,那么无论它是如何打包的,都是必需的。

相反,并非所有 BCL都需要具有有效的C#实现。这是因为语言规范并不需要所有BCL类型。例如,System.Exception(请参阅#16.2)和NullReferenceException是必需的,但实现C#语言不需要FileNotFoundException

请注意,即使规范提供了基本类型的最小定义(例如System.String),它也不会定义常用的方法(例如String.Replace)。也就是说,几乎所有的BCL都 语言规范 1 的范围。


  

..但我的结论是语言的设计确实取决于类库中特定元素的存在和行为。

我完全同意并且已经包含上述示例(以及此类定义的限制)。

  

..如果我要设计一种新的编程语言,我会使用什么技术将“throw”的语义映射到特殊类“Exception”?

我不会主要看C#规范,而是看看Common Language Infrastructure规范。出于实际原因,这种新语言应该设计为与现有的CLI / CLR语言互操作,但不一定需要“成为C#”。

1 CLI(及相关参考资料)定义最小BCL的要求。因此,如果认为有效的C#实现必须符合(或可能采用)CLI,那么还有许多其他类型需要考虑,而这些类型在C#规范本身中没有提到。


不幸的是,我对第二个(也是更有趣的)问题没有足够的了解。

答案 3 :(得分:0)

我的印象是

使用C#和Ada等语言

应用程序源代码是可移植的

标准库源代码不可移植

跨编译器/实现