我一直想知道如何从编程语言到其库来管理依赖项。以C#为例。当我开始学习计算时,我会假设(错误地证明)语言本身是独立于最终可用于它的类库而设计的。也就是说,首先定义一组语言关键字(例如for
,class
或throw
)加上语法和语义,并且可以从语言中使用的库是单独开发的。我曾经认为,这些库中的特定类不应该对语言的设计产生任何影响。
但这不起作用,或者不是一直都行不通。考虑throw
。 C#编译器确保throw
后面的表达式解析为异常类型。 Exception
是库中的一个类,因此它根本不应该是特殊的。除了C#编译器为其指定特殊语义之外,它将与其他任何类一样。这是非常好的,但我的结论是语言的设计确实取决于类库中特定元素的存在和行为。
此外,我想知道如何管理这种依赖。如果我要设计一种新的编程语言,我会用什么技术将throw
的语义映射到Exception
这个非常特殊的类?
所以我的问题是两个:
谢谢。
EDIT。感谢那些指出我的第二个问题非常含糊的人。我同意。我想要学习的是编译器存储的所需类型的引用。例如,它是否通过某种唯一ID找到类型?发布新版本的编译器或类库时会发生什么?我知道这仍然很模糊,我不期待一个精确的单段答案;相反,非常欢迎指向文学或博客文章。
答案 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等语言
应用程序源代码是可移植的
标准库源代码不可移植
跨编译器/实现