揭穿 Scala 神话

发布于 2024-09-27 11:22:30 字数 307 浏览 6 评论 0原文

关于 Scala 语言最常见的误解是什么?有哪些反例?

更新

我更多地思考了我所看到的各种说法,例如“Scala 是动态类型的”和“Scala 是一种脚本语言”。

我承认“Scala 是[简单/复杂]”可能被认为是一个神话,但这也是一个非常依赖于上下文的观点。我个人的信念是,完全相同的功能可以使 Scala 显得简单或复杂,具体取决于使用它们的人。最终,语言只是提供抽象概念,而使用这些抽象概念的方式塑造了人们的看法。

不仅如此,它还有一定的煽动争论的倾向,而且我还没有看到任何人改变对这个话题的坚定观点......

What are the most commonly held misconceptions about the Scala language, and what counter-examples exist to these?

UPDATE

I was thinking more about various claims I've seen, such as "Scala is dynamically typed" and "Scala is a scripting language".

I accept that "Scala is [Simple/Complex]" might be considered a myth, but it's also a viewpoint that's very dependent on context. My personal belief is that it's the very same features that can make Scala appear either simple or complex depending oh who's using them. Ultimately, the language just offers abstractions, and it's the way that these are used that shapes perceptions.

Not only that, but it has a certain tendency to inflame arguments, and I've not yet seen anyone change a strongly-held viewpoint on the topic...

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

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

发布评论

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

评论(13

傻比既视感 2024-10-04 11:22:30

误解:Scala 支持运算符重载。

实际上,Scala 只是具有非常灵活的方法命名规则和用于方法调用的中缀语法,以及当中缀语法与“运算符”一起使用时确定方法优先级的特殊规则。与真正的运算符重载(a la C++)相比,这种微妙的区别对于该语言功能的实用性和潜在的滥用具有重要影响,正如 James Iry 对 这个问题

Myth: Scala supports operator overloading.

Actually, Scala just has very flexible method naming rules and infix syntax for method invocation, with special rules for determining method precedence when the infix syntax is used with 'operators'. This subtle distinction has critical implications for the utility and potential for abuse of this language feature compared to true operator overloading (a la C++), as explained more thoroughly in James Iry's answer to this question.

2024-10-04 11:22:30

误区:方法和函数是同一回事。

事实上,函数是一个值(FunctionN 类之一的实例),而方法则不是。 Jim McBeath 更详细地解释了这些差异。最重要的实际区别是:

  • 仅方法可以具有类型参数
  • 仅方法可以采用隐式参数
  • 仅方法可以具有命名参数和默认参数
  • 引用方法时,通常需要使用下划线来区分方法调用和部分函数应用(例如 str.length 计算结果为数字,而 str.length _ 计算结果为零参数函数。

Myth: methods and functions are the same thing.

In fact, a function is a value (an instance of one of the FunctionN classes), while a method is not. Jim McBeath explains the differences in greater detail. The most important practical distinctions are:

  • Only methods can have type parameters
  • Only methods can take implicit arguments
  • Only methods can have named and default parameters
  • When referring to a method, an underscore is often necessary to distinguish method invocation from partial function application (e.g. str.length evaluates to a number, while str.length _ evaluates to a zero-argument function).
ㄖ落Θ余辉 2024-10-04 11:22:30

我不同意 Scala 很难的观点,因为你可以使用非常高级的功能来用它来做困难的事情。 Scala 的可扩展性意味着您可以在 Scala 本身中编写 DSL 抽象和高级 API,否则需要语言扩展。因此,为了公平起见,您需要将 Scala 库与其他语言编译器进行比较。人们不会说 C# 很难,因为(我想,没有这方面的第一手知识)C# 编译器相当难以理解。对于 Scala 来说,一切都是公开的。但我们需要明确一点,大多数人不需要也不应该这样做。

I disagree with the argument that Scala is hard because you can use very advanced features to do hard stuff with it. The scalability of Scala means that you can write DSL abstractions and high-level APIs in Scala itself that otherwise would need a language extension. So to be fair you need to compare Scala libraries to other languages compilers. People don't say that C# is hard because (I assume, don't have first hand knowledge on this) the C# compiler is pretty impenetrable. For Scala it's all out in the open. But we need to get to a point where we make clear that most people don't need to write code on this level, nor should they do it.

守不住的情 2024-10-04 11:22:30

我认为许多 scala 开发人员(以及 EPFL 的开发人员(还有你自己,Kevin))的一个常见误解是“scala 是一种简单的语言”。争论通常是这样的:

  • scala 有很少的关键字
  • scala 重用了相同的很少的结构(例如,PartialFunction 语法被用作catch 块)
  • scala 有一些简单规则,允许您创建库代码(可能看起来好像该语言具有特殊关键字/结构)。我在这里想到的是隐含的;包含冒号的方法;允许的标识符符号; X(a, b)a X b 与提取器等效。 scala
  • declaration-site 差异意味着类型系统会妨碍你。不再需要通配符和 吗? super T

我个人的观点是这个论点完全是假的。 Scala 的类型系统与隐式一起允许编写 坦率地说,对于普通开发人员来说是难以理解的代码。任何其他建议都是荒谬的,无论上述“指标”可能会引导您思考什么。 (请注意,我在 Twitter 和其他地方看到的那些嘲笑 Java 不复杂性的人恰好是超级聪明的人,有时他们似乎在使用 monad、函子和箭头之前就已经掌握了这些知识。穿短裤)。

反对这一点的明显论据是(当然):

  1. 您不必必须编写这样的代码,
  2. 您不必迎合平均开发人员

其中,它在我看来,只有#2 是有效的。无论您编写的代码是否像 scalaz 一样复杂,我认为使用这种语言是愚蠢的(并继续使用它),但对类型系统没有真正的了解。还有什么方法可以充分利用这门语言呢?

I think a common misconception amongst many scala developers, those at EPFL (and yourself, Kevin) is that "scala is a simple language". The argument usually goes something like this:

  • scala has few keywords
  • scala reuses the same few constructs (e.g. PartialFunction syntax is used as the body of a catch block)
  • scala has a few simple rules which allow you to create library code (which may appear as if the language has special keywords/constructs). I'm thinking here of implicits; methods containing colons; allowed identifier symbols; the equivalence of X(a, b) and a X b with extractors. And so on
  • scala's declaration-site variance means that the type system just gets out of your way. No more wildcards and ? super T

My personal opinion is that this argument is completely and utterly bogus. Scala's type system taken together with implicits allows one to write frankly impenetrable code for the average developer. Any suggestion otherwise is just preposterous, regardless of what the above "metrics" might lead you to think. (Note here that those who I've seen scoffing at the non-complexity of Java on Twitter and elsewhere happen to be uber-clever types who, it sometimes seems, had a grasp of monads, functors and arrows before they were out of short pants).

The obvious arguments against this are (of course):

  1. you don't have to write code like this
  2. you don't have to pander to the average developer

Of these, it seems to me that only #2 is valid. Whether or not you write code quite as complex as scalaz, I think it's just silly to use the language (and continue to use it) with no real understanding of the type system. How else can one get the best out of the language?

厌倦 2024-10-04 11:22:30

有一种误解认为 Scala 很难,因为 Scala 是一种复杂的语言。

这是错误的——从各种指标来看,Scala 并不比 Java 复杂。 (语法的大小、代码行数或标准 API 中的类数或方法数等。)

但不可否认的是,Scala 代码可能非常难以理解。如果 Scala 不是一门复杂的语言,怎么会这样呢?

答案是 Scala 是一种强大语言。 Java 有许多特殊的构造(如枚举)来完成一件特定的事情,并且要求您学习仅适用于该一件事情的专门语法,而 Java 则不同,Scala 有多种非常通用的构造。通过混合和匹配这些结构,人们可以用很少的代码表达非常复杂的想法。而且,毫不奇怪,如果有人没有同样复杂的想法,并试图弄清楚你在用这个非常紧凑的代码做什么,他们可能会发现它令人畏惧 - 甚至比他们看到几个更令人畏惧的代码页来做同样的事情,从那时起,至少他们会意识到有多少概念性的东西需要理解!

还有一个问题是事情是否比实际需要的更复杂。例如,集合库中存在的一些类型体操使集合使用起来很有趣,但实施或扩展却令人困惑。这里的目标并不是特别复杂(例如子类应该返回自己的类型),但是所需的方法(更高种类的类型、隐式构建器等)很复杂。 (事实上​​,如此复杂,以至于 Java 只是放弃并且不尝试,而不是像 Scala 那样“正确”地执行它。此外,原则上,希望这在未来会得到改进,因为该方法可以发展更紧密地匹配目标。)在其他情况下,目标很复杂; list.filter(_<5).sorted.grouped(10).flatMap(_.tail.headOption) 有点乱,但如果你真的想取所有小于 5 的数字,然后从剩余列表中的 10 个数字中取出每第二个数字,好吧,这只是一个有点复杂的想法,如果您了解基本的集合操作,代码几乎说明了它的作用。

总结:Scala 并不复杂,但它可以让你紧凑地表达复杂的想法。复杂想法的紧凑表达可能令人望而生畏。


有一种误解认为 Scala 是不可部署的,而许多第三方 Java 库可以毫不犹豫地部署。

就这个神话的存在而言,我怀疑它存在于那些不习惯将虚拟机和 API 与语言和编译器分开的人们中。如果您认为 java == javac == Java API,那么如果有人建议使用 scalac 而不是 javac,您可能会有点紧张,因为您会看到 JVM 运行得有多好。

Scala 最终成为 JVM 字节码,加上它自己的自定义库。没有理由更担心小规模部署 Scala 或作为其他大型项目的一部分,因为部署任何其他库可能会或可能不会与您喜欢的 JVM 兼容。诚然,Scala 开发团队的支持力度不如 Google 集合或 Apache Commons,但其背后的影响力至少与 Java Advanced Imaging 项目等一样多。

There is a myth that Scala is difficult because Scala is a complex language.

This is false--by a variety of metrics, Scala is no more complex than Java. (Size of grammar, lines of code or number of classes or number of methods in the standard API, etc..)

But it is undeniably the case that Scala code can be ferociously difficult to understand. How can this be, if Scala is not a complex language?

The answer is that Scala is a powerful language. Unlike Java, which has many special constructs (like enums) that accomplish one particular thing--and requires you to learn specialized syntax that applies just to that one thing, Scala has a variety of very general constructs. By mixing and matching these constructs, one can express very complex ideas with very little code. And, unsurprisingly, if someone comes along who has not had the same complex idea and tries to figure out what you're doing with this very compact code, they may find it daunting--more daunting, even, than if they saw a couple of pages of code to do the same thing, since then at least they'd realize how much conceptual stuff there was to understand!

There is also an issue of whether things are more complex than they really need to be. For example, some of the type gymnastics present in the collections library make the collections a joy to use but perplexing to implement or extend. The goals here are not particularly complicated (e.g. subclasses should return their own types), but the methods required (higher-kinded types, implicit builders, etc.) are complex. (So complex, in fact, that Java just gives up and doesn't try, rather than doing it "properly" as in Scala. Also, in principle, there is hope that this will improve in the future, since the method can evolve to more closely match the goal.) In other cases, the goals are complex; list.filter(_<5).sorted.grouped(10).flatMap(_.tail.headOption) is a bit of a mess, but if you really want to take all numbers less than 5, and then take every 2nd number out of 10 in the remaining list, well, that's just a somewhat complicated idea, and the code pretty much says what it does if you know the basic collections operations.

Summary: Scala is not complex, but it allows you to compactly express complex ideas. Compact expression of complex ideas can be daunting.


There is a myth that Scala is non-deployable, whereas a wide range of third-party Java libraries can be deployed without a second thought.

To the extent that this myth exists, I suspect it exists among people who are not accustomed to separating a virtual machine and API from a language and compiler. If java == javac == Java API in your mind, you might get a little nervous if someone suggests using scalac instead of javac, because you see how nicely your JVM runs.

Scala ends up as JVM bytecode, plus its own custom library. There's no reason to be any more worried about deploying Scala on a small scale or as part of some other large project as there is in deploying any other library that may or may not stay compatible with whichever JVM you prefer. Granted, the Scala development team is not backed by quite as much force as the Google collections, or Apache Commons, but its got at least as much weight behind it as things like the Java Advanced Imaging project.

折戟 2024-10-04 11:22:30

误区二:

def foo() = "something"

def bar = "something"

是一样的。

它不是;您可以调用 foo(),但 bar() 尝试不带参数调用 StringLike 的 apply 方法(导致错误)。

Myth:

def foo() = "something"

and

def bar = "something"

is the same.

It is not; you can call foo(), but bar() tries to call the apply method of StringLike with no arguments (results in an error).

东京女 2024-10-04 11:22:30

与 Actors 库相关的一些常见误解:

  • Actors 在多个线程中/针对线程池并行处理传入消息(事实上,在多个线程中处理消息与 Actors 概念相反,可能会导致竞争情况 - 所有消息都是按顺序进行的)在一个线程中处理(基于线程的参与者使用一个线程进行邮箱处理和执行;基于事件的参与者可以共享一个VM线程来执行,使用多线程执行器来安排邮箱处理))
  • 未捕获的异常不会改变参与者的行为/state(事实上,所有未捕获的异常都会终止 actor)

Some common misconceptions related to Actors library:

  • Actors handle incoming messages in a parallel, in multiple threads / against a thread pool (in fact, handling messages in multiple threads is contrary to the actors concept and may lead to racing conditions - all messages are sequentially handled in one thread (thread-based actors use one thread both for mailbox processing and execution; event-based actors may share one VM thread for execution, using multi-threaded executor to schedule mailbox processing))
  • Uncaught exceptions don't change actor's behavior/state (in fact, all uncaught exceptions terminate the actor)
腻橙味 2024-10-04 11:22:30

误区:当计算从零开始求和之类的内容时,您可以将折叠替换为归约。

这是 Scala 新用户中常见的错误/误解,尤其是那些没有函数式编程经验的用户。以下表达式等效:

seq.foldLeft(0)(_+_)

seq.reduceLeft(_+_)

这两个表达式的不同之处在于处理空序列的方式:fold 生成有效结果 (0),而reduce 抛出异常。

Myth: You can replace a fold with a reduce when computing something like a sum from zero.

This is a common mistake/misconception among new users of Scala, particularly those without prior functional programming experience. The following expressions are not equivalent:

seq.foldLeft(0)(_+_)

seq.reduceLeft(_+_)

The two expressions differ in how they handle the empty sequence: the fold produces a valid result (0), while the reduce throws an exception.

洋洋洒洒 2024-10-04 11:22:30

误区:模式匹配不'非常适合 OO 范式

Martin Odersky 本人此处揭穿了这一点。 (另请参阅这篇论文 - Matching Objects with Patterns - 作者:Odersky 等人。)

Myth: Pattern matching doesn't fit well with the OO paradigm.

Debunked here by Martin Odersky himself. (Also see this paper - Matching Objects with Patterns - by Odersky et al.)

从此见与不见 2024-10-04 11:22:30

误区:this.type 指代 this.getClass 所表示的相同类型。

作为这种误解的一个例子,人们可能会假设在以下代码中 v.me 的类型是 B

trait A { val me: this.type = this }

class B extends A

val v = new B

实际上,this.type > 指的是唯一实例为 this 的类型。一般来说,x.type 是单例类型,其唯一实例是x。所以在上面的例子中,v.me的类型是v.type。以下会议演示了该原理:

scala> val s = "a string"
s: java.lang.String = a string

scala> var v: s.type = s
v: s.type = a string

scala> v = "another string"
<console>:7: error: type mismatch;
 found   : java.lang.String("another string")
 required: s.type
       v = "another string"

Myth: this.type refers to the same type represented by this.getClass.

As an example of this misconception, one might assume that in the following code the type of v.me is B:

trait A { val me: this.type = this }

class B extends A

val v = new B

In reality, this.type refers to the type whose only instance is this. In general, x.type is the singleton type whose only instance is x. So in the example above, the type of v.me is v.type. The following session demonstrates the principle:

scala> val s = "a string"
s: java.lang.String = a string

scala> var v: s.type = s
v: s.type = a string

scala> v = "another string"
<console>:7: error: type mismatch;
 found   : java.lang.String("another string")
 required: s.type
       v = "another string"
划一舟意中人 2024-10-04 11:22:30

Scala 具有类型推断和细化类型(结构类型),而 Java 没有。

这个神话被打破詹姆斯·艾里.

Scala has type inference and refinement types (structural types), whereas Java does not.

The myth is busted by James Iry.

成熟的代价 2024-10-04 11:22:30

误区:Scala 具有高度可扩展性,但没有限定什么形式的可扩展性。

Scala 在表达高级指称语义的能力方面确实具有高度可扩展性,这使得它成为一种非常适合实验的语言,甚至可以在自上而下协调的项目级规模上扩展生产强>组合性。

然而,每种引用不透明语言(即允许可变数据结构)都是命令性的(而不是声明性的),并且不会扩展到 WAN 自下而上、不协调的组合性和安全性。换句话说,命令式语言对于模块的不协调开发来说是组合(和安全)意大利面条。我意识到这种不协调的发展目前可能被大多数人认为是一个“白日梦”,因此可能不是一个高度优先的事项。这并不是要贬低更高级别语义统一可以提供的组合性(即消除极端情况)的好处,例如 标准库的范畴论模型

许多读者可能会出现严重的认知失调,特别是因为对于命令式与声明式(即可变与不可变)存在普遍的误解,(以及渴望与懒惰,) 例如,一元语义从来都不是天生命令式的 然而,这是一个谎言。是的,在 Haskell 中 IO monad 是命令式的,但它是命令式的与它是一个 monad 无关。

我在“Copute 教程”和“Purity”部分中对此进行了更详细的解释,这些部分位于主页或暂时位于 此链接

我的观点是,我非常感谢 Scala 的存在,但我想澄清一下 Scala 可以扩展什么,不能扩展什么。我需要 Scala,因为它做得很好,即对我来说,它是构建新的声明性语言原型的理想平台,但 Scala 本身并不完全是声明性的,据我所知,Scala 编译器无法强制执行引用透明性,除了记住使用val 无处不在。

我认为我的观点适用于有关 Scala 的复杂性争论。我发现(到目前为止,主要是概念性的,因为到目前为止我对新语言的实际经验有限)消除了可变性和循环,同时保留 钻石多重继承子类型(Haskell没有) ,从根本上简化了语言。例如,Unit 虚构消失了,afaics、一系列其他问题和构造变得不必要,例如非范畴论标准库、用于理解等。

Myth: that Scala is highly scalable, without qualifying what forms of scalability.

Scala may indeed be highly scalable in terms of the ability to express higher-level denotational semantics, and this makes it a very good language for experimentation and even for scaling production at the project-level scale of top-down coordinated compositionality.

However, every referentially opaque language (i.e. allows mutable data structures), is imperative (and not declarative) and will not scale to WAN bottom-up, uncoordinated compositionality and security. In other words, imperative languages are compositional (and security) spaghetti w.r.t. uncoordinated development of modules. I realize such uncoordinated development is perhaps currently considered by most to be a "pipe dream" and thus perhaps not a high priority. And this is not to disparage the benefit to compositionality (i.e. eliminating corner cases) that higher-level semantic unification can provide, e.g. a category theory model for standard library.

There will possibly be significant cognitive dissonance for many readers, especially since there are popular misconceptions about imperative vs. declarative (i.e. mutable vs. immutable), (and eager vs. lazy,) e.g. the monadic semantic is never inherently imperative yet there is a lie that it is. Yes in Haskell the IO monad is imperative, but it being imperative has nothing to with it being a monad.

I explained this in more detail in the "Copute Tutorial" and "Purity" sections, which is either at the home page or temporarily at this link.

My point is I am very grateful Scala exists, but I want to clarify what Scala scales and what is does not. I need Scala for what it does well, i.e. for me it is the ideal platform to prototype a new declarative language, but Scala itself is not exclusively declarative and afaik referential transparency can't be enforced by the Scala compiler, other than remembering to use val everywhere.

I think my point applies to the complexity debate about Scala. I have found (so far and mostly conceptually, since so far limited in actual experience with my new language) that removing mutability and loops, while retaining diamond multiple inheritance subtyping (which Haskell doesn't have), radically simplifies the language. For example, the Unit fiction disappears, and afaics, a slew of other issues and constructs become unnecessary, e.g. non-category theory standard library, for comprehensions, etc..

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