8

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

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

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

所以我的问题有两个:

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

谢谢你。

编辑。感谢那些指出我的第二个问题非常模糊的人。我同意。我想了解的是编译器存储了哪些关于它需要的类型的引用。例如,它是否通过某种唯一 id 来查找类型?当新版本的编译器或类库发布时会发生什么?我知道这仍然很模糊,并且我不希望有一个精确的单段答案;相反,最欢迎指向文学或博客文章的指针。

4

4 回答 4

11

我想了解的是编译器存储了哪些关于它需要的类型的引用。例如,它是否通过某种唯一 id 来查找类型?

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

例如,当 C# 编译器需要检查抛出的表达式是否派生自 System.Exception 或与 System.Exception 相同时,它会假装在 上进行全局命名空间查找System,然后在 上进行查找Exception,找到类,然后进行比较将生成的类信息转换为为表达式推导的类型。

编译器团队使用这种技术,因为无论我们是在编译您的源代码并且System.Exception在元数据中,或者如果我们正在编译 mscorlib 本身并且System.Exception在源代码中,它都可以工作。

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

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

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

这个问题,再一次,含糊不清。制作新的编译器版本必须发生什么?很多工作,这就是必须发生的事情。

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

我写了一篇关于 C# 语言及其编译器设计等内容的博客。它位于http://ericlippert.com

于 2013-05-07T20:08:09.593 回答
5

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

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

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

我可以看到编写类似 C 的语言,这对于汇编程序来说基本上是一种更令人愉悦的语法,而无需库。但是你怎么可能写,比如说,async-await没有那个人Task<T>在你房间里设计呢?这似乎是一种挫折的练习。

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

在 C# 的情况下,是的,绝对是。为了正常工作,C# 语言假定有几十种类型可用并按文档说明。

在我发现他自己编写的IEnumerable<T>方法与真正的IEnumerable<T>. 他的问题的解决方案:不要那样做。

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

我什至不知道如何开始回答这个难以置信的模糊问题。

于 2013-05-07T19:21:13.810 回答
3

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

如果语言规范中需要该类型,那么它是必需的——不管它是如何打包的。

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

请注意,尽管规范为基本类型(例如System.String)提供了最少的定义,但它并没有定义普遍接受的方法(例如String.Replace)。也就是说,几乎所有的 BCL 都在语言规范1的范围之外


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

我完全同意并在上面包含了示例(以及此类定义的限制)。

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

我不会主要看 C# 规范,而是看公共语言基础设施规范。实际上,这种新语言应该被设计为与现有的 CLI/CLR 语言互操作,但不一定需要“是 C#”。

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


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

于 2013-05-07T18:59:53.747 回答
0

我的印象是

在 C# 和 Ada 等语言中

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

标准库源代码不可移植

跨编译器/实现

于 2013-11-08T11:08:28.840 回答