В чем разница между классом и типом в Scala (и Java)?


Скала

где могут наблюдаться различия между классом и типом в Scala и почему это различие важно?

это только рассмотрение с точки зрения дизайна языка или это "практическое" влияние при программировании Scala?

или это фундаментально для "обеспечения границ" системы типов (Nothing,Null заходите на мой ум)?

Java

сколько из соображений / различий / проблем, упомянутых выше, также могут быть распознаны в Java?


(смотрите, в чем разница между типом и классом? как язык-агностическое введение.)

4   51  

4 ответа:

когда вы говорите "тип", я предполагаю, что вы имеете в виду статический тип в основном. Но я скоро расскажу о динамических типах.

статический тип-это свойство части программы, которое может быть статически доказано (статический означает "без его запуска"). В статически типизированном языке каждое выражение имеет тип, независимо от того, пишете вы его или нет. Например, в Cish "int x = a * b + c - d", a,b,c и d имеют типы, a * b имеет тип, a * b + c имеет тип и a * B + c-d имеет тип. Но мы только аннотировали x с типом. В других языках, таких как Scala, C#, Haskell, SML и F#, даже это не было бы необходимо.

именно то, что свойства доказуемы, зависит от проверки типа.

класс стиля Scala, с другой стороны, является просто спецификацией для набора объектов. Эта спецификация включает в себя некоторую информацию о типе и включает в себя множество деталей реализации и представления, таких как тела методов и частные поля и т. д. В Scala a класс также определяет некоторые границы модуля.

многие языки имеют типы, но не имеют классов, и многие языки имеют классы, но не имеют (статических) типов.

есть несколько заметных различий между типами и классами. List [String] - это тип, но не класс. В Scala List-это класс, но обычно не тип (на самом деле это более высокий тип). В C# List это не тип любого рода, а в Java это "сырой тип".

Scala предлагает структурные типы. {def foo: Bar} означает любой объект, который доказуемо имеет метод foo, который возвращает бар, независимо от класса. Это тип, но не класс.

типы могут быть разделены с помощью параметров типа. Когда вы пишете def foo[T] (x : T) = ..., то внутри тела foo T является типом. Но это не класс.

типы могут быть виртуальными в Scala (т. е. "абстрактные члены типа"), но классы не могут быть виртуальными с Scala сегодня (хотя есть шаблонный тяжелый способ кодирования виртуального классы https://wiki.scala-lang.org/display/SIW/VirtualClassesDesign)

теперь, динамические типы. Динамические типы, свойства объектов, которые среда выполнения автоматически проверяет перед выполнением определенных операций. В динамически типизированных языках OO на основе классов существует сильная корреляция между типами и классами. То же самое происходит на языках JVM, таких как Scala и Java, которые имеют операции, которые могут быть проверены только динамически, такие как отражение и литье. В этих языках "стирание типа" более или менее означает, что динамический тип большинства объектов совпадает с их классом. Более или менее. Это не относится, например, к массивам, которые обычно не стираются, чтобы среда выполнения могла определить разницу между Array[Int] и Array[String]. Но помните мое широкое определение "динамические типы, свойства объектов, которые среда выполнения автоматически проверяет."При использовании отражения можно отправить любое сообщение на любом объекте. Если объект поддерживает это сообщение, то все работает. Таким образом, имеет смысл говорить обо всех объектах, которые могут крякать как утка, как динамический тип, хотя это не класс. Это суть того, что сообщества Python и Ruby называют "утиной типизацией"."Кроме того, по моему широкому определению даже "zeroness" является динамическим типом в том смысле, что в большинстве языков среда выполнения автоматически проверяет числа, чтобы убедиться, что вы не делите на ноль. Существует очень мало языков, которые могут доказать, что статически, делая ноль (или не-ноль) статическим типом.

наконец, как упоминали другие, есть типы, такие как int, которые не имеют класса в качестве детали реализации, типы, такие как Null и Any, которые немного особенные, но могут иметь классы и не имеют, и типы, такие как Nothing, которые даже не имеют никаких значений, не говоря уже о классе.

хорошо, я укушу... У Джеймса есть хороший ответ, поэтому я собираюсь попробовать другой такт и дать более приземленную точку зрения.

вообще говоря, класс что-то, что может быть инстанцирован. одноэлементные объекты (scala) черты (Scala) и интерфейсы (Scala) также обычно считаются классами. Это имеет смысл, поскольку синглтоны все еще создаются (с помощью кода, сгенерированного компилятором), и интерфейс может быть создан как часть производный класс.

это подводит нас ко второму пункту. классы являются основной единицей проектирования в большинстве объектно-ориентированных языков (хотя и не основанных на прототипах, таких как javascript). Полиморфизм и подклассы определяются в терминах классов. классы также предоставляют пространство имен и элементы управления видимостью.


типы-это очень разные звери, каждое возможное значение, которое может выразить система, будет иметь один или несколько типов, и их иногда можно приравнять к классам, например:

(Int) => String // both the type and class are Function1[Int,String]
"hello world" // class and type are String    

вы также получаете некоторые интересные различия между Scala и Java с:

7 // both the class and type are Int in Scala
  // in Java there's no class and the type is Integer.TYPE

println("hello world") // the return type is Unit, of class Unit
                       // Java has void as a type, but no corresponding class

error("oops") // the type and class are both "Nothing"

и действительно забавные типы, которые вообще не являются классами. Например, this.type всегда относится к уникальному типу this. Он уникален для одного экземпляра и даже не совместим с другими экземплярами того же класса.

есть также абстрактные типы и параметры типа. Например:

type A // 'A' is an undetermined abstract type
       // to be made concrete in a subclass

class Seq[T] { ... } // T is a type, but not a class

Seq is интересно, как это класс, но не тип. Точнее, это "конструктор типов"; что-то, что построит допустимый тип при предоставлении необходимого параметра типа. Другой термин для конструкторов типов - "более высокие типы", мне лично не нравится этот термин, поскольку "конструктор типов" побуждает меня думать в терминах предоставления типов, как и любая другая форма аргумента - ментальная модель, которая хорошо послужила мне для Scala.

"высший род" справедливо подразумевает, что Seq имеет "вид", который * => *, это обозначение гласит, что Seq возьмет один тип и даст один тип (это похоже на нотацию карри для описания функций). Для сравнения, вид Map и * => * => * потому что он принимает два параметра типа.

тип может быть полезен сам по себе, без каких-либо экземпляров. Один пример для этого называется "фантомный тип". Вот пример для Java: http://michid.wordpress.com/2008/08/13/type-safe-builder-pattern-in-java/

в этом примере мы имеем public static class Initializer<HA, HB>, где HA и HB возьмите некоторые типы (представленные абстрактными классами TRUE и FALSE), не будучи создан.

Я надеюсь, что это показывает, что типы и классы что-то разные, и эти типы могут быть полезны сами по себе.

(только Java) я бы сказал, что тип-это набор объектов. Объект o тип X, если o является членом set X. Типа X это подтипа на Y, если значение X это подмножество на Y.

для каждого класса C (не интерфейса) существует набор объектов, созданных из new C(...). Интересно, что мы редко заботимся об этом наборе. (но каждый объект действительно принадлежит к такому набору, что может быть полезно)

для каждого класса C существует тип t(C), обычно упоминается как "Тип C", который представляет собой набор всех объектов, которые могут быть созданы из new S(...) где S-C или подкласс C.

аналогично, для каждого интерфейса I существует тип t(I), "тип I", который представляет собой набор всех объектов, которые могут быть созданы из new S(...) где S реализует I.

очевидно, что если класс S является наследником C, тип S-это подтип типа С. похожие на интерфейс I

существует тип null, который является пустым набором. Тип null является подтипом каждого типа.

есть совокупность всех объектов, который является объектом типа. Это супер тип каждого типа.

пока что этот формализм довольно бесполезен. Тип в основном совпадает с классом или интерфейсом, а отношение подтипа-это в основном отношение подкласса/подинтерфейса. Тривиальность-это хорошо, язык понятно! Но, вводя дженерики, существуют более сложные типы и операции, такие как объединения и пересечения типов. Типы больше не являются только классами и интерфейсами, а отношения подтипов намного богаче и сложнее для понимания.