Почему Java нуждается в интерфейсах, а Smalltalk - нет? - PullRequest
14 голосов
/ 02 ноября 2011

Я некоторое время программировал на Smalltalk, но мне никогда не требовались интерфейсы для реализации чего-либо. Тогда почему языки, такие как Java, не могут избавиться от интерфейсов? Это только Smalltalk или есть другой язык, который не нуждается в интерфейсах?

Ответы [ 5 ]

24 голосов
/ 02 ноября 2011

Поскольку Java статически типизирован, а Smalltalk - нет.Интерфейсы не служат какой-либо цели, когда вы не объявляете типы и ваши переменные не будут проверяться на наличие типов.Но в статически типизированном языке, таком как Java, они чрезвычайно удобны, потому что они позволяют вам иметь переменную, тип которой определяется методами, которые реализует объект, а не его класс.Это значительно приближает вас к динамическому типированию, изначально встроенному в Smalltalk, не отказываясь от преимуществ проверки типов.

9 голосов
/ 02 ноября 2011

Это проблема полиморфизма: в Java у вас есть статические типы, и поэтому вам нужно знать, на какие сообщения может отвечать ваш объект ... в Smalltalk (и других нестатических языках) вам просто нужно реализовать правильные методы, чтобы иметь полиморфизм,

Например:

  • В Java вам нужно реализовать Cloneable, который определяет метод Cloneable.clone, чтобы иметь объекты cloneble.Затем компилятор знает, что ваш объект поймет этот метод (в противном случае он выдаст ошибку)
  • В smalltalk вам просто нужно реализовать метод #clone.Компилятор никогда не знает / не заботится о том, какие сообщения понимают ваши объекты, до тех пор, пока он не будет вызван.

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

Этот способ ведения дел часто называют «набором утки» ... см .: http://en.wikipedia.org/wiki/Duck_typing

1 голос
/ 03 ноября 2011

Как вы думаете, может быть полезна роль "интерфейсов" в Smalltalk?

См. - Добавление динамических интерфейсов в Smalltalk

0 голосов
/ 10 февраля 2018

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

Во время выполнения интерфейсы не могут быть принудительно применены ни в одном языке, поскольку все динамические объекты являются либо 1. структурами чистого состояния, либо 2. структурами чистого состояния, причем первый член является указателем на отображение виртуальной таблицы либо целыми числами для членов (через массив) или строки для членов (будучи словарем / хэш-картой).Следствием этого является то, что вы всегда можете изменить значения в индексах виртуальной таблицы, или в записях хеш-карты, или просто изменить указатель виртуальной таблицы на другой адрес виртуальной таблицы или просто недопустимый доступ к памяти.

Smalltalk может иметьлегко сохраняемая информация, предоставляемая во время компиляции ваших классов, и таким образом, это то, как intellisense в браузерах smalltalk дает предложения членам, но на самом деле это не пойдет на пользу smalltalk.

Существует несколько проблем с синтаксисом smalltalk, которыеограничивает использование интерфейсов.


  1. Smalltalk имеет только один основной тип

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

Компилятор может выбрать тип для вывода переменных, которые были назначены, но философские объекты smalltalk возражают против этого.


Методы Smalltalk всегда принимают один аргумент

Может показаться, что выполнение myArray at: 1 put: 'hi' имеет два аргумента, но на самом деле вы вызываете эквивалентный javascript myArray ['at: put:']([1, 'hi']) с myArray, являющимся объектом (~ hashmap).количество аргументов, таким образом, не может быть проверено без нарушения философии smalltalk.

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


smalltalk выставляет свой компилятор во время выполнения, тогда как java очень старается скрыть компилятор от времени исполнения.

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

Одним из следствий этого является то, что у класса может быть один интерфейс в одной точке программы, но на полпути в программе пользователь изменил класс, чтобы иметь другой интерфейс;если пользователь хочет использовать этот интерфейс во время компиляции (после изменения класса с использованием кода), компилятор должен быть намного умнее, чтобы понять, что класс, который не поддерживает ".Greet ()", теперь внезапно делает это или перестаетделает, или что метод ".Greet ()" и метод ".Foo ()" поменялись местами.

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


в отличие от C ++, smalltalk не использует массивы для vtables, вместо этого он использует карты из строк в объекты.Это означает, что даже если вы знаете, что метод существует в вызываемом классе, вы не можете оптимизировать его до dispid, чтобы будущие вызовы этого метода использовали смещение массива вместо хеширования для поиска метода.Чтобы продемонстрировать это, давайте используем javascript:

Текущие объекты smalltalk ведут себя аналогично этому:

var myIntVtbl = {'+': function (self, obj1) {return {lpVtbl: myIntVtbl, data: self.data + obj1.data};}};var myInt1 = {lpVtbl: myIntVtbl, data: 2};var myInt2 = {lpVtbl: myIntVtbl, data: 5};var myInt3 = myInt1 ['lpVtbl'] ['+'] (myInt1, myInt2);var myInt4 = myInt3 ['lpVtbl'] ['+'] (myInt3, myInt3);var myInt5 = myInt4 ['lpVtbl'] ['+'] (myInt4, myInt4);console.log (myInt5);

каждый раз, когда мы вызываем +, мы должны хешировать '+', чтобы получить член из словаря vtable.Java работает аналогично, поэтому декомпиляторы могут так легко называть имена методов.

Одна оптимизация, которую может выполнить компилятор, если он знает интерфейсы, - это компилировать строки в dispids, например:

var myIntVtbl = [function (self, obj1) {return {lpVtbl: myIntVtbl, data: self.data + obj1.data};}];

var myInt1 = {lpVtbl: myIntVtbl, data: 2};var myInt2 = {lpVtbl: myIntVtbl, data: 5};var myInt3 = myInt1 ['lpVtbl'] [0] (myInt1, myInt2);var myInt4 = myInt3 ['lpVtbl'] [0] (myInt3, myInt3);var myInt5 = myInt4 ['lpVtbl'] [0] (myInt4, myInt4);console.log (myInt5);

Насколько я знаю, ни java, ни smalltalk не делают этого для классов, тогда как C ++, C # (через атрибут comvisible) делают.


Подводя итогsmalltalk может использовать интерфейсы, что, в свою очередь, становится все более похожим на PHP, но во время компиляции он не получит никаких преимуществ, кроме слабых заверений.

Аналогично, Java не нуждается в интерфейсах, буквально можетработайте как smalltalk при условии, что вы предоставляете java-компилятор java для большей доступности.Чтобы почувствовать это, вы можете взаимодействовать между java и jashascript-движком nashorn, который поставляется со всеми текущими java-наборами, и использовать его функцию 'eval' в качестве компилятора времени выполнения.Java может легко избавиться от интерфейсов и использовать рефлексивный полиморфизм, обрабатывать все как объекты, но будет гораздо более многословно общаться с объектами, не позволяя вам индексировать по строке, и перегружать оператор индекса для строки для динамического поиска членов.

0 голосов
/ 02 ноября 2011

не уверен, что именно вы спрашиваете (точнее, на какой вопрос вы больше всего хотите получить ответ), но взгляните на Ruby.Насколько я понимаю, это намного ближе к разговорной речи, чем Java.

Если бы я ответил на вопрос о том, зачем java нужны интерфейсы, я бы сказал что-то о том, что java является статически типизированным языком и использует эту философиюТо, что делает Java, - это то, что делает для нужд интерфейсов.Эффективно интерфейсы пытаются дать вам что-то вроде множественного наследования в Java без проблем множественного наследования, с которыми сталкиваются другие языки (я верю в C ++).

...