В теории языка программирования тип - это набор значений. Например, тип "int" - это набор всех целочисленных значений.
В языках ООП класс - это тип, не так ли?
Когда класс определен с более чем одним членом, например
class myclass{
int a;
double b;
}
Когда мы говорим о классе, мы имеем в виду
- «
(a,b)
гдеa
int иb
двойник», или - "{
(x,y)
|x
- это любое int,y
любое двойное}"?
Что означает экземпляр myclass
?
- «
(a,b)
гдеa
int иb
двойник», или - объект, который занимает пространство памяти и который может (не обязательно, т. е. может быть пустым) хранить
(x,y)
, гдеx
находится какое-либо целое иy
любое двойное число?
a
иb
являются членами этого типа, как упоминает Киллиан Форт. Myclass изоморфен записям с полямиa
иb
типаint
иdouble
- вы можете взять такую запись и превратить ее в экземплярmyclass
.Ответы:
Ни.
Насколько я понимаю, вы спрашиваете, достаточно ли одного и того же набора типов полей для классификации как одного и того же класса, или же они должны называться одинаково. Ответ таков: «Даже одного и того же типа и одинаковых имен недостаточно!» Структурно эквивалентные классы не обязательно совместимы по типу.
Например, если у вас есть класс a
CartesianCoordinates
иPolarCordinates
класс, они могут иметь два числа в качестве своих полей, и они могут даже иметь одинNumber
и тот же тип и одинаковые имена, но они все равно не будут совместимы, и экземпляр классаPolarCoordinates
не будет экземплярCartesianCoordinates
. Возможность разделять типы по назначению, а не по их текущей реализации, является очень полезной частью написания более безопасного и более удобного в обслуживании кода.источник
interface
в Java и C #, если вы когда-нибудь захотите провести модульное тестирование. Вы заканчиваете тем, что пишете кучу шаблонов, чтобы вы могли изменить определенный класс, который будет использовать ваша программа, даже если вы не собираетесь менять его во время выполнения.Типы не являются наборами.
Видите ли, теория множеств имеет ряд особенностей, которые просто не применимы к типам, и наоборот . Например, объект имеет один канонический тип. Это может быть экземпляр нескольких разных типов, но только один из этих типов использовался для его создания. Теория множеств не имеет понятия «канонических» множеств.
Теория множеств позволяет вам создавать подмножества на лету , если у вас есть правило, которое описывает, что принадлежит подмножеству. Теория типов вообще не позволяет этого. В то время как большинство языков имеют
Number
тип или что - то подобное, они не имеютEvenNumber
типа, и не было бы просто создать. Я имею в виду, достаточно просто определить сам тип, но любые существующиеNumber
s, которые оказываются даже, не будут волшебным образом преобразованы вEvenNumber
s.На самом деле, говорить, что вы можете «создавать» подмножества, несколько неискренне, потому что наборы - это совсем другой вид животных. В теории множеств эти подмножества уже существуют во всех бесконечных способах их определения. В теории типов мы обычно ожидаем иметь дело с конечным (если большим) числом типов в любой момент времени. Говорят, что существуют только те типы, которые мы фактически определили, а не каждый тип, который мы могли бы определить.
Наборы не могут прямо или косвенно содержать себя . Некоторые языки, такие как Python, предоставляют типы с менее регулярными структурами (в Python
type
канонический тип естьtype
иobject
считается экземпляромobject
). С другой стороны, большинство языков не позволяют пользовательским типам участвовать в подобном обмане.Наборы обычно допускают перекрытие, не будучи заключенными друг в друга. Это редко встречается в теории типов, хотя некоторые языки поддерживают ее в форме множественного наследования. Другие языки, такие как Java, допускают только ограниченную форму или полностью ее запрещают.
Пустой тип существует (он называется нижним типом ), но большинство языков его не поддерживают или не рассматривают как тип первого класса. «Тип, который содержит все другие типы», также существует (он называется верхним типом ) и широко поддерживается, в отличие от теории множеств.
NB . Как ранее указывали некоторые комментаторы (до того как поток был перемещен в чат), можно моделировать типы с помощью теории множеств и других стандартных математических конструкций. Например, вы можете моделировать членство в типе как отношение, а не моделировать типы как наборы. Но на практике это намного проще, если вы используете теорию категорий вместо теории множеств. Так Хаскелл моделирует свою теорию типов, например.
Понятие «подтип» действительно очень отличается от понятия «подмножество». Если
X
это подтипY
, это означает, что мы можем заменить экземплярыY
на экземпляры,X
и программа все равно будет «работать» в некотором смысле. Это скорее поведенческий, чем структурный характер, хотя некоторые языки (например, Go, Rust, возможно, C) выбрали последний из соображений удобства либо для программиста, либо для языковой реализации.источник
Алгебраические типы данных - способ обсудить это.
Существует три основных способа комбинирования типов:
Товар. Это в основном то, о чем вы думаете:
тип продукта; его значения - все возможные комбинации (то есть кортежи) одного
int
и одногоdouble
. Если вы рассматриваете типы чисел как наборы, то количество элементов типа продукта фактически является результатом количества элементов поля.Сумма. В процедурных языках это немного неудобно выражать напрямую (классически это делается с помощью теговых объединений ), поэтому для лучшего понимания, вот тип суммы в Haskell:
значения этого типа имеют либо форму
AnInt 345
, либоADouble 4.23
, но всегда используется только одно число (в отличие от типа продукта, где каждое значение имеет два числа). Итак, кардинальность: сначала вы перечисляете всеInt
значения, каждое из которых должно быть объединено сAnInt
конструктором. Плюс ко всему, всеDouble
значения в сочетании сADouble
. Отсюда тип суммы .Возведение в степень 1 . Я не буду обсуждать это подробно здесь, потому что оно не имеет четкой ОО-корреспонденции вообще.
Так что насчет классов? Я сознательно использовал ключевое слово,
struct
а неclass
дляIntXDouble
. Дело в том, что класс как тип на самом деле не характеризуется своими полями, это просто детали реализации. Ключевым фактором является то, какие различимые значения могут иметь класс.Что это отношение , хотя это, значение того или иного класса может быть значения любого из его подклассов ! Таким образом, класс на самом деле является типом суммы, а не типом продукта: если
A
иB
оба будут производнымиmyClass
, тоmyClass
, по сути, будет суммойA
иB
. Независимо от фактической реализации.1 Это функции (в математическом смысле! ); тип функции
Int -> Double
представлен экспоненциальнымDouble
Int
. Плохо, если у вашего языка нет правильных функций ...источник
static
методы, за исключением того, что они все еще не являются первоклассными значениями. Суть большинства языков OO в том, что они воспринимают объекты как наименьший строительный блок, поэтому, если вы хотите что-то меньшее, вы должны имитировать это объектами, и вы все равно в конечном итоге перетаскиваете кучу семантических функций, которых не должно быть. Например, не имеет смысла сравнивать функции на равенство, но вы все равно можете сравнивать два объекта с поддельными функциями.Извините, но я не знаю о "сырой" теории. Я могу предоставить только практический подход. Я надеюсь, что это приемлемо для программистов. Я не знаком с этикетом здесь.
Центральная тема ООП - сокрытие информации . Что именно представляют собой члены класса, должны быть неинтересны для его клиентов. Клиент отправляет сообщения (вызывает методы / функции-члены) экземпляра, которые могут изменить или не изменить внутреннее состояние. Идея состоит в том, что внутренняя часть класса может измениться, без влияния на клиента.
Следствием этого является то, что класс отвечает за обеспечение того, чтобы его внутреннее представление оставалось «допустимым». Давайте предположим класс, который хранит (упрощенный) номер телефона в двух целых числах:
Это данные членов класса. Тем не менее, класс, вероятно, будет намного больше, чем просто его члены данных, и он определенно не может быть определен как «набор всех возможных значений int x int». Вы не должны иметь прямого доступа к данным членов.
Построение экземпляра может отрицать любые отрицательные числа. Возможно, конструкция также каким-то образом нормализует ареакод или даже проверяет целое число. Таким образом , вы бы в конечном итоге гораздо ближе к вашему
"(a,b) where a is an int and b is a double"
, потому что это , конечно , не какой - либо два ИНТ хранится в этом классе.Но это не имеет большого значения, если речь идет о классе. Это не тип членов данных, ни диапазон их возможных значений, которые определяют класс, это методы , которые определены для него.
Пока эти методы остаются прежними, разработчик может изменять типы данных на числа с плавающей запятой, BIGNUM, строки и т. Д., И для всех практических целей это будет тот же класс .
Существуют шаблоны проектирования, позволяющие гарантировать, что такие изменения внутреннего представления могут быть сделаны без ведома клиента (например, идиома pimpl в C ++, которая скрывает любые элементы данных за непрозрачным указателем ).
источник
It is neither the type of the data members, nor the range of their possible values that defines the class, it's the methods that are defined for it.
Члены данных не определяют класс только тогда, когда вы их скрываете. Это может быть самый распространенный случай, но нельзя сказать, что это верно для всех классов. Если хотя бы одно поле является публичным, оно так же важно, как и его методы.class
. (Маркировка ихfinal
помогает понять смысл, но все же).protected
Тем не менее, у вас все еще есть проблема с членами, которые могут быть унаследованы и, таким образом, являются частью второго API для разработчиков подклассов.protected
насколько это возможно на практике. ;-))class
является зависимой от языка конструкцией. Насколько я знаю,class
в теории типов такого понятия не существует .Типа является описанием категории / диапазон значений, составных структур, или что у вас. OOPwise, это похоже на «интерфейс». (В не зависящем от языка смысле. Не так сильно
int
зависит от языка. В Java, например, это тип , но он не имеет отношения кinterface
. Спецификации открытых / защищенных полей также не являются частьюinterface
, но являются частью "интерфейса" или типа .)Главное, что это гораздо больше семантическое определение, чем конкретное. Структурируйте только факторы, поскольку выявляемые поля / поведение и их определенные цели совпадают. Если у вас нет обоих, у вас нет совместимости типов.
Класс является реализацией типа. Это шаблон, который на самом деле определяет внутреннюю структуру, прикрепленное поведение и т. Д.
источник