Java не нуждается в интерфейсах.Это то, что компилятор решил поддерживать, а не отбрасывать.
Во время выполнения интерфейсы не могут быть принудительно применены ни в одном языке, поскольку все динамические объекты являются либо 1. структурами чистого состояния, либо 2. структурами чистого состояния, причем первый член является указателем на отображение виртуальной таблицы либо целыми числами для членов (через массив) или строки для членов (будучи словарем / хэш-картой).Следствием этого является то, что вы всегда можете изменить значения в индексах виртуальной таблицы, или в записях хеш-карты, или просто изменить указатель виртуальной таблицы на другой адрес виртуальной таблицы или просто недопустимый доступ к памяти.
Smalltalk может иметьлегко сохраняемая информация, предоставляемая во время компиляции ваших классов, и таким образом, это то, как intellisense в браузерах smalltalk дает предложения членам, но на самом деле это не пойдет на пользу smalltalk.
Существует несколько проблем с синтаксисом smalltalk, которыеограничивает использование интерфейсов.
- 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 может легко избавиться от интерфейсов и использовать рефлексивный полиморфизм, обрабатывать все как объекты, но будет гораздо более многословно общаться с объектами, не позволяя вам индексировать по строке, и перегружать оператор индекса для строки для динамического поиска членов.