用超出规范允许范围的动态语言编写程序

发布于 2024-08-12 23:07:57 字数 1416 浏览 3 评论 0原文

随着动态类型语言的发展,它们给我们带来了更大的灵活性,人们很可能会编写超出规范允许范围的程序。

当我读到 bobince 的回答时,我的思考受到了这个问题的影响: 一个关于 JavaScript 的切片和拼接方法的问题

基本思想是 Javascript 中的 splice 被指定仅在某些情况下使用,但是,它可以在其他情况下使用,并且该语言无法阻止它,因为该语言被设计得极其灵活。

除非有人仔细阅读规范并决定遵守它,否则我相当肯定会发生很多此类违规行为。

这是一个问题,还是编写如此灵活的语言的自然延伸?或者我们应该期望像 JSLint 这样的工具来帮助成为规范警察吗?

我喜欢这个问题中的一个答案,即 python 的实现就是规范。我很好奇这是否真的更接近这些类型语言的事实,基本上,如果该语言允许你做某事,那么它就在规范中。 有 Python 语言规范吗?

更新:

阅读了几条评论后,我想我应该检查规范中的拼接方法,这就是我在第 104 页底部找到的内容,http://www.mozilla.org/js/language/E262-3.pdf,所以看来我可以在子数组上使用 splice 而不会违反规范。我只是不想让人们陷入我的例子中,但希望能够考虑这个问题。

    The splice function is intentionally generic; it does not require that its this value be an Array object. 
Therefore it can be transferred to other kinds of objects for use as a method. Whether the splice function 
can be applied successfully to a host object is implementation-dependent.

更新2: 我对 javascript 不感兴趣,但对语言灵活性和规范感兴趣。例如,我希望 Java 规范指定您不能将代码放入接口中,但使用 AspectJ 我经常这样做。这可能是一种违规,但作者并没有预测到 AOP,而且该工具足够灵活,可以用于此用途,就像 JVM 对于 Scala 和 Clojure 也足够灵活一样。

With the growth of dynamically typed languages, as they give us more flexibility, there is the very likely probability that people will write programs that go beyond what the specification allows.

My thinking was influenced by this question, when I read the answer by bobince:
A question about JavaScript's slice and splice methods

The basic thought is that splice, in Javascript, is specified to be used in only certain situations, but, it can be used in others, and there is nothing that the language can do to stop it, as the language is designed to be extremely flexible.

Unless someone reads through the specification, and decides to adhere to it, I am fairly certain that there are many such violations occuring.

Is this a problem, or a natural extension of writing such flexible languages? Or should we expect tools like JSLint to help be the specification police?

I liked one answer in this question, that the implementation of python is the specification. I am curious if that is actually closer to the truth for these types of languages, that basically, if the language allows you to do something then it is in the specification.
Is there a Python language specification?

UPDATE:

After reading a couple of comments, I thought I would check the splice method in the spec and this is what I found, at the bottom of pg 104, http://www.mozilla.org/js/language/E262-3.pdf, so it appears that I can use splice on the array of children without violating the spec. I just don't want people to get bogged down in my example, but hopefully to consider the question.

    The splice function is intentionally generic; it does not require that its this value be an Array object. 
Therefore it can be transferred to other kinds of objects for use as a method. Whether the splice function 
can be applied successfully to a host object is implementation-dependent.

UPDATE 2:
I am not interested in this being about javascript, but language flexibility and specs. For example, I expect that the Java spec specifies you can't put code into an interface, but using AspectJ I do that frequently. This is probably a violation, but the writers didn't predict AOP and the tool was flexible enough to be bent for this use, just as the JVM is also flexible enough for Scala and Clojure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

恋竹姑娘 2024-08-19 23:07:57

一种语言是静态类型还是动态类型实际上只是问题的一小部分:静态类型的语言可能会使代码更容易强制执行其规范,但勉强是这里的关键词。只有“契约式设计”——一种允许您明确声明先决条件、后置条件和不变量,并执行它们的语言——才能帮助您防止库的用户凭经验发现库到底允许他们做什么逃脱惩罚,并利用这些发现超越您的设计意图(可能会限制您未来更改设计或其实现的自由)。主流语言不支持“契约设计”——Eiffel 是最接近这一点的,现在很少有人会称其为“主流”——大概是因为它的成本(主要是不可避免地在运行时)似乎并不其优点是合理的。 “参数 x 必须是素数”,“方法 A 必须先被调用,然后才能调用方法 B”,“一旦调用了方法 D,就不能再调用方法 C”,等等——典型的类型您想要声明的约束(并且已隐式强制执行,而不必自己花费大量编程时间和精力检查它们)只是不适合在以下上下文中构建它们:静态类型语言的编译器几乎无法强制执行。

Whether a language is statically or dynamically typed is really a tiny part of the issue here: a statically typed one may make it marginally easier for code to enforce its specs, but marginally is the key word here. Only "design by contract" -- a language letting you explicitly state preconditions, postconditions and invariants, and enforcing them -- can help ward you against users of your libraries empirically discovering what exactly the library will let them get away with, and taking advantage of those discoveries to go beyond your design intentions (possibly constraining your future freedom in changing the design or its implementation). And "design by contract" is not supported in mainstream languages -- Eiffel is the closest to that, and few would call it "mainstream" nowadays -- presumably because its costs (mostly, inevitably, at runtime) don't appear to be justified by its advantages. "Argument x must be a prime number", "method A must have been previously called before method B can be called", "method C cannot be called any more once method D has been called", and so on -- the typical kinds of constraints you'd like to state (and have enforced implicitly, without having to spend substantial programming time and energy checking for them yourself) just don't lend themselves well to be framed in the context of what little a statically typed language's compiler can enforce.

梦巷 2024-08-19 23:07:57

我认为只要您的方法是围绕定义良好的接口而不是一些人为的外部“类型”元数据设计的,这种灵活性就是一个优势。大多数数组函数只需要一个具有 length 属性的对象。事实上,它们都可以通用地应用于许多不同类型的对象,这对于代码重用来说是一个福音。

任何高级语言设计的目标都应该是减少完成工作所需编写的代码量,而不会过多损害可读性。需要编写的代码越多,引入的错误就越多。限制类型系统(如果设计得不好)在最坏的情况下可能是一个普遍的谎言,在最好的情况下可能是一个过早的优化。我不认为过度限制的类型系统有助于编写正确的程序。原因是该类型仅仅是一种断言,不一定基于证据。

相比之下,数组方法检查其输入值以确定它们是否具有执行其功能所需的内容。这就是鸭子类型,我相信这更科学和“正确”,并且它会产生更多可重用的代码,这正是您想要的。您不希望方法拒绝您的输入,因为他们的论文没有按顺序排列。这就是共产主义。

I think that this sort of flexibility is an advantage as long as your methods are designed around well defined interfaces rather than some artificial external "type" metadata. Most of the array functions only expect an object with a length property. The fact that they can all be applied generically to lots of different kinds of objects is a boon for code reuse.

The goal of any high level language design should be to reduce the amount of code that needs to be written in order to get stuff done- without harming readability too much. The more code that has to be written, the more bugs get introduced. Restrictive type systems can be, (if not well designed), a pervasive lie at worst, a premature optimisation at best. I don't think overly restrictive type systems aid in writing correct programs. The reason being that the type is merely an assertion, not necessarily based on evidence.

By contrast, the array methods examine their input values to determine whether they have what they need to perform their function. This is duck typing, and I believe that this is more scientific and "correct", and it results in more reusable code, which is what you want. You don't want a method rejecting your inputs because they don't have their papers in order. That's communism.

找个人就嫁了吧 2024-08-19 23:07:57

我认为您的问题与动态类型与静态类型没有太大关系。确实,我可以看到两种情况:一方面是马丁·克莱顿提到的达夫装置之类的东西;另一方面是像马丁·克莱顿提到的达夫装置那样的东西。当你第一次看到它时,这种用法是非常令人惊讶的,但它是语言语义明确允许的。如果有一个标准,这种习惯用法可能会作为具体示例出现在该标准的后续版本中。这些都没有什么问题;事实上,它们可以(除非过度使用)极大地提高生产力。

另一种情况是编程到实现。这种情况可能是实际的滥用,要么是由于对标准的无知,要​​么是缺乏标准,要么是单一实现,或者是具有不同语义的多个实现。问题在于,以这种方式编写的代码在最好的情况下是不可在实现之间移植的,在最坏的情况下会限制该语言的未来发展,因为担心添加优化或功能会破坏主要应用程序。

I do not think your question really has much to do with dynamic vs. static typing. Really, I can see two cases: on one hand, there are things like Duff's device that martin clayton mentioned; that usage is extremely surprising the first time you see it, but it is explicitly allowed by the semantics of the language. If there is a standard, that kind of idiom may appear in later editions of the standard as a specific example. There is nothing wrong with these; in fact, they can (unless overused) be a great productivity boost.

The other case is that of programming to the implementation. Such a case would be an actual abuse, coming from either ignorance of a standard, or lack of a standard, or having a single implementation, or multiple implementations that have varying semantics. The problem is that code written in this way is at best non-portable between implementations and at worst limits the future development of the language, for fear that adding an optimization or feature would break a major application.

风渺 2024-08-19 23:07:57

在我看来,原来的问题有点不合理。如果规范明确允许特定行为(如“必须”、“可以”、“应该”或“应该”),那么根据定义,任何允许/实现该行为的编译器/解释器都与该语言兼容。这似乎是OP在评论部分提出的情况 - JavaScript规范据说*说有问题的函数可以在不同的情况下使用,因此它是明确允许的。

另一方面,如果编译器/解释器实现或允许规范明确禁止的行为,则根据定义,编译器/解释器在规范之外运行。

还有第三种情况,以及一个相关的、定义明确的术语,用于描述规范未定义行为的情况:未定义。如果规范实际上没有指定给定特定情况的行为,则该行为是未定义的,并且可能由编译器/解释器有意或无意地处理。然后,开发人员有责任认识到该行为不是规范的一部分,并且如果她/他选择利用该行为,则开发人员的应用程序将依赖于特定的实现。提供实现的解释器/编译器没有义务维护超出向后兼容性和生产者可能做出的任何承诺的官方未定义的行为。此外,语言规范的后续迭代可能会定义先前未定义的行为,从而使编译器/解释器要么(a)不符合新迭代,要么(b)推出新补丁/版本以变得兼容,从而破坏旧版本。

*“据说”是因为我自己还没有看到规范。我遵循上面的陈述。

It seems to me that the original question is a bit of a non-sequitor. If the specification explicitly allows a particular behavior (as MUST, MAY, SHALL or SHOULD) then anything compiler/interpreter that allows/implements the behavior is, by definition, compliant with the language. This would seem to be the situation proposed by the OP in the comments section - the JavaScript specification supposedly* says that the function in question MAY be used in different situations, and thus it is explicitly allowed.

If, on the other hand, a compiler/interpreter implements or allows behavior that is expressly forbidden by a specification, then the compiler/interpreter is, by definition, operating outside the specification.

There is yet a third scenario, and an associated, well defined, term for those situations where the specification does not define a behavior: undefined. If the specification does not actually specify a behavior given a particular situation, then the behavior is undefined, and may be handled either intentionally or unintentionally by the compiler/interpreter. It is then the responsibility of the developer to realize that the behavior is not part of the specification, and, should s/he choose to leverage the behavior, the developer's application is thereby dependent upon the particular implementation. The interpreter/compiler providing that implementation is under no obligation to maintain the officially undefined behavior beyond backwards compatibility and whatever commitments the producer may make. Furthermore, a later iteration of the language specification may define the previously undefined behavior, making the compiler/interpreter either (a) non-compliant with the new iteration, or (b) come out with a new patch/version to become compliant, thereby breaking older versions.

* "supposedly" because I have not seen the spec, myself. I go by the statements made, above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文