Здравствуйте, AndrewVK, Вы писали:
AVK>Мое предложение — множественное наследование интерфейсов и отсутствие наследования реализаций. Т.е. классы вообще не наследуются. А для реюза кода придумать способ упрощения агрегации.
Я тоже за эту идею. И хочу еще одну штуку, тесно связанную с отсутствием наследования реализаций. Я хочу избавиться от new ... и "конструкторов" как таковых. Методы "создания" объектов — это "обычные" с точки зрения всего остального кода статические методы.
Сама идея вполне естественно возникает в тех языках, где функция — объект первого класса. Периодически во всякие трансформаторы (вроде map и т.п.) хочется скормить конструктор объекта. А нельзя

. Чисто теоретически, можно сделать синтаксическую конструкцию вида "map (new SomeClass) ... и это будет работать. Но останется еще одна проблема — перегрузка конструктора по имени и "неравноправие" конструкторов. Пример:
public class Rectangle {
public Rectangle(int x, int y, int width, int height) {...}
public static Rectangle createByPoints(int x1, int y1, int x2, int y2) { return new Rectangle(x1, y1, x2-x1, y2-y1); }
}
Проверки и т.п. можно добавить. createByPoints можно с двумя точками сделать, но я не хочу (для данного примера). Логичное решение здесь — сделать еще статический метод createByPointAndSize, а конструктор сделать приватным. Но все равно остается лишний код конструктора и обертка к нему. Немного, но писать все же лень.
Объясню, почему фича связана с наследованием реализаций. Классический "конструктор" в языках с наследованием реализаций на самом деле является инициализатором. Он не создает новый объект, а инициализирует существующий. Создать объект он не может потому, что не знает точную структуру объекта (может создаваться его наследник). Поэтому выделение объекта переложили на "пользователя" конструктора, и в коде создали оператор new. Синтаксически, наверное, можно было генерировать статические методы для создания объектов, но полностью от конструкторов отказаться не получилось бы (не ясно, где вызов родительского инициализатора, а где — создание нового объекта). Без наследования реализации любой "конструктор" теперь точно знает структуру объекта, который нужно создавать. Поэтому может и выделять память.
Как примерно это может выглядеть:
public class Rectangle {
public constructor byPointAndSize(int x, int y, int width, int height) { this.x = x; this.y = y; ... }
public static Rectangle byPoints(int x1, int y1, int x2, int y2) { return Rectange.byPointsAndSize(x1, y1, x2-x1, y2-y1); }
public constructor square(int x, int y, int width) {
initialize byPointAndSize(x, y, width, width);
}
}
Конструктор (constructor) — это с точки зрения всего остального кода static <T> метод. T — класс, внутри которого объявлен конструктор. Все остальные модификаторы (доступ и т.п.) — как обычно. Внутри метода ведет себя почти как instance method (т.е. имеет this). Почти, потому что имеет специальную форму — вызов других инициализаторов ininialize(аналог существующих вызовов других конструкторов из конструктора). Соответственно, при генерации и выполнении сначала выделяется память и затем вызывается инициализатор (с уже существующим this). initialize — вызов другого инициализатора (без выделения памяти!). На вызов initialize можно навесить те же ограничения, которые навешиваются на вызов других конструкторов из конструктора (например, может быть только первым statement в конструкторе).
Итого. Вроде бы реализуемо. И получаются "first class constructors", которые являются обычными статическими методами. По синтаксису в простейших случаях можно сделать очень похожим на "стандартные" конструкторы, вместо new Point(3, 5) будет Point.new(3,5). Так что простые сценарии подобный подход не усложняет.