Comments 103
Для сего, очевидно, нужно не только добавить в язык то, чего там не было, но и убрать из языка многое из того, что там было
Вот только джава уже на протяжении двух десятилетий сохраняет обратную совместимость, и похоже никто не собирается менять эти чудесные традиции.
То же касается и комментариев: сложилась практика (по-моему, весьма адская) плюсовать и минусовать комментарии исходя из экспертности. То есть, если человек пишет в ответ «а мне нравится по-другому», и тебе нравится как-то иначе, нужно сжечь собеседника минусами в комментарий. Это опять же неявно подразумевает, что минусующий считает, что его собеседник знает правду и намеренно распространяет ложь. Люди слишком привыкли, что существует не более одного формата общения — того, в котором целый тред пытается что-то доказать друг другу. Отсюда например, часто встречающийся паттерн «лесенки минусов» (все комментарии в ветке — перепалка двух человек, которые минусуют друг друга) или «лесенки чётных минусов» (та же перепалка, но сообщество решило, что виноват чётный оправдывающийся, и его минусят сразу десятками, сотнями). Формат обсуждения, когда люди просто пытаются в ходе обсуждения найти какое-то решение в это никак не помещается.
Что с этим делать — непонятно. Наверное, вначале зарабатывать некий капитал из плюсов и потом сливать его на нестандартных статьях, пытаясь выработать привычку читать что-то кроме экспертных статей.
В частности если человек предлагает реформировать язык программирования, то предполагается, что они знает, в общих чертах, хотя бы десяток самых известных-распространённых и может как-то сравнивать их плюсы и минусы.
Ну ведь не будете же вы выкладывать на Хабр статью о том, как вы написали свою первую сортировку пузырьком? Да даже и
merge sort in place
(хотя это сложный достаточно алгоритм) — тоже не будете. А обсуждаемая статья — это примерно этот уровень и комментарии это только подтверждают."Ничего не понимает" — это вещь относительная. То, что пишет мидл — это какая-то постыдная чепуха для сеньора. И наоборот, то что пишет джун — откровение для новичка. Для вашей прабабушки вы всегда будете "компьютерным гением". Требование всегда "чего-то понимать" означает, что вы наложили на автора поста или комментария обязанность быть экспертом в обсуждаемой теме, экспертнее чем большинство на Хабре. Вроде как если бы уроки математики в школе мог вести только академик.
И — нет, нету такого правила, что каждый писатель и улучшатель обязан быть экспертом. Уверен, что половина улучшений происходит потому, что человеку лень разбираться с какой-то сложной механикой, он откладывает сложную книгу на миллион страниц о сложной фиче и придумывает другую — свою, простую. В результате на следующей итерации мы имеем, например, более простые и понятные фреймворки, которые можно понять за в два раза меньшее количество страниц. Улучшения иногда делают те, кто не разобрался.
Когда-то давно мне казалось, что если я не понимаю код, это значит — я тупой и нужно учиться. Сейчас пришло понимание, что если я не понимаю код, то скорей всего — код очень, очень плох :-)
Дискуссия между обычными людьми (не экспертами) часто выглядит так: люди говорят в рамках своих крайне лимитированных знаний и в конце концов, дополняя дыры в понимании друг друга, приходят к каким-то выводам. Результат разговора не обязательно будет корректный, но зато все получат удовольствие и узнают что-то новое. Это обычный разговор о истории в курилке, например: два коллеги-программиста обсуждают какую-то войну в V веке, о которой помнят лишь по обрывкам институтских лекций и в ходе этого диалога упражняются, например, в логике. Никто из адекватных людей не бьёт друг другу лицо в курилке и не бьётся в конвульсиях от того, что кто-то из собеседников не прав в отношении войны в V веке!
Подумайте, что ваши категоричные суждения о тех или иных вещах, скорей всего, кажутся смешными и наивными в глазах какого-нибудь дизайнера языка. который занимается этим на работе все ближайшие 30 лет.
Запретить все разговоры в курилке? Поставить там крупнокалиберный пулемёт и разрывать на куски мяса всех, кто сказал нечто, противоречащее школьному учебнику (то есть, вообще всех)? Не хотел бы жить в таком мире.
> Ну ведь не будете же вы выкладывать на Хабр статью о том, как вы написали свою первую сортировку пузырьком?
Ещё как буду! Помойму там есть много чего обсудить и спросить у экспертов, что и как правильно писать.
То, что пишет мидл — это какая-то постыдная чепуха для сеньора.Это кто ж вам такую чушь сказал? Миддл, в пределах своей компетенции, пишет вещи не хуже сеньора. Просто есть вещи, в которых он некомпетентен… и об этих вещах — он ничего не пишет и не должен писать.
Требование всегда «чего-то понимать» означает, что вы наложили на автора поста или комментария обязанность быть экспертом в обсуждаемой теме, экспертнее чем большинство на Хабре.Разумеется! А иначе какой смысл писать статью? О предмете, в котором вы не разбираетесь?
Вроде как если бы уроки математики в школе мог вести только академик.Нет, это как если бы уроки математики в школе вёл физрук. Для комедии — сойдёт, а для Хабра — нет.
Уверен, что половина улучшений происходит потому, что человеку лень разбираться с какой-то сложной механикой, он откладывает сложную книгу на миллион страницо сложной фиче и придумывает другую — свою, простую.На чём, извините, уверенность основана? У вас есть примеры?
Улучшения иногда делают те, кто не разобрался.Иногда — да. Но очень-очень редко. В большинстве случаев улучшения как раз делаются теми, кто разобрался — и понял что и откуда можно выкинуть.
Запретить все разговоры в курилке?Нет, зачем. Запретить туда набиваться тысяче человек одновременно. Это и негигиенично и шум будет черезмерный.
Одно дело — когда вы обсуждаете что-то со свомими 5-6-10 лучшими друзьями, совсем другое — когда вы вовлекаете в это тысячи людей, и совсем третьей — когда вы о чём-то говорите с тысячами экспертов на конференции.
Хабр находится где-то посредине между курилкой и конференцией: от вас не ожидается, что вы будете экспертом — но какой-то уровень компетенции должен-таки быть.
> Разумеется! А иначе какой смысл писать статью?
Такой же, как у разговора в курилке. Приятно пообщаться и узнать что-то новое в комментариях.
Больше скажу, признанные эксперты так делают доклады на профильных конференциях. Например, пару дней назад на FOSDEM (крупнейшая в мире free open source конференция), на джава-треке, Christine H Flood (наверное, не надо ее представлять? это дизайнер языков включая Java и LISP с десятками лет опыта, работающая сейчас в RedHat) рассказала просто о проекте, которым она занимается по фану. Нет, она не продумала хорошо то, что делает, и о чем собирается говорить, и половина ответов на вопросы звучала как "я делегирую эту проблему утилите CRIU, она может быть это делает… а может быть и нет, спросите у её автора, он тут есть на конференции". От этого у многих в зале конкретно бомбануло, они ожидали от человека такого уровня чего-то более другого, более масштабного, каких-то громких заявлений от имени RedHat — и ничего этого не было. А я наоборот радовался — вся жизнь прошла, а девушка так и не потеряла способности относиться к происходящему легко, как к игре, как к искусству, без всей этой фигни вида "я эксперт с N-цать летним стажем, сейчас расскажу, что вам делать". Она пришла на сцену просто чтобы поджечь интересную дискуссию, и своей цели добилась!
от вас не ожидается, что вы будете экспертом — но какой-то уровень компетенции должен-таки быть.
А вот не говорите мне, пожалуйста, что от меня ожидается, а что — нет. Работодатель может рассказывать, что от меня ожидается, и то только потому, что там договор на сорок страниц с подписью кровью. Рандом в курилке? Не думаю. Лично мне интересно приятно общаться — этим я и занимаюсь.
В частности, сейчас мы обсуждаем какие-то вопросы организации сообщества, в которых не являемся не то что экспертами, вообще никем. По вашей логике, вы не имеете права писать комментарий вот тот, что выше, нужно звать сразу Дениса Крючкова :)
От этого у многих в зале конкретно бомбануло, они ожидали от эксперта такого уровня чего-то более другого, более масштабного и экспертного.И они, в общем, были правы.
Она пришла на сцену просто чтобы поджечь интересную дискуссию, и своей цели добилась!Это иногда работает с «живой» аудиторией (хотя почти всегда это — результат недостатка времени на подготовку, так что приходится «вытягивать» провальное, по сути, выступление, за счёт харизмы). И почти никогда не работает в интернете.
Хинт: есть специальные Q&A сайты, где подразумевается, что ответы даются не просто из желания почесать языком, а технически грамотные советы. Например, Тостер или StackOverflow. На SO за попытку флуда в комментариях придут кровавые модераторы и турецкими саблями разрисуют хулигана под хохлому. Там это официальное правило, что "Дума SO — не место для дискуссий", там всё как вы хотите. На SO никогда не случился бы диалог, который мы ведём сейчас.
На Хабре — с этим особо не борются. Но тратить время и силы на объяснение того, что человек и так, вроде как, должен знать (если он собрался рассуждать на определённые темы) редко кто будет.
Весь этот мерзкий тривиум на самом деле пошёл от чудака Сократа, который очень хорошо понимал то, что ничего не понимает. Такое не каждому дано. Т.е., «ничего не понимает» это комплимент и ещё какой. После Сократа жила старушка Грейс Хоппер, автор Кобола, одной из целей которой было максимально приблизить конструкции Кобола английскому языку, и ещё в 2006 году Кобол считался языком программирования, на котором было написано больше всего строк кода — из Википедии. Двуногим же без перьев типа меня обычно и приходится юзать всё такое гениальное, а вдруг и правда гениальное — я же не спорю. JavaScript был там кем-то из нетскейп что ли написан за десять дней чтобы только не визжал бейсик. И опять чувак попал в струю. Очевидно, я так не умею, но мне приходится с этим иметь дело.
P.S. По поводу языков, которые «оказались в нужное время в нужном месте»… JavaScript это ещё не «ужас летящий на крыльях ночи». Настоящий ужас — это Perl и PHP. По крайней мере JavaScript был рождён из очень пристойного языка, пусть и сильно изуродованного. Perl и PHP — были рождены примерно тем методом, про который вы говорите… и многие году люди занимаются тем, что пытаются их «выпрямить»… с не слишком большим успехом, прямо скажем.
Что с этим делать — непонятно.
Отлично понятно.
- Никакое сообщество не может саморегулироваться. Это аксиома. Нужны хоть какие-то модераторы.
- За минус в карму нужно ставить минус в карму самому минусующему. Это чуть-чуть сбалансирует "потенциал саморегулирования" у людей с нарушением зрения, видящим либо чёрное, либо белое и ни одного оттенка серого.
Для «protected», «default» и «public» полей автогенерация сеттеров и геттеров компилятором, без автогенерации видимых сорцов, но с возможностью их перегрузки.
Было бы круто. А если бы делфишный property осилили так и вообще молодцы были бы.
Property — это такое псевдополе класса при попытка записи в которое вызывается соотвествующая функция, а при попытке чтения — другая (в частном случае одной из них может не быть, тогда чтение или запись осуществляются «напрямую»).
В Java вам на каждую переменную нужно создавать две функции, чтобы было «по феншую». Геттер и сеттер. Даже если эти функции ничего не делают с переменной, просто кладут её в поле класса и вынивают из него.
Дальше — бесконечные автогенераторы и прочая мура.
В C# (и, как прародителя, но не изобретатели, этой фичи, в Delphi) вы просто объявляете переменную
public
— и… всё. А если позже оказывается, что всё-таки нужно что-то делать при изменения поля — то вместо этого поля заводится property.Это лучше вашего предложения более естественным синтаксисом. Ну можно
window.width = 125;
выглядит понятнее, чем window.setWidth(125);
С присваиванием все просто — доступ к полю приоритетнее, и тогда ничего из уже написанного не сломается. И даже хрен с ним уж с присваиванием — пусть так и оставят setXXX(). Главная задача пропертей — это добавить сахорочку и уменьшить бойлерплейт на этапе определения объекта. Потому как более чем в 99% случаем все ваши геттеры-сеттеры — это тупо автогенерация доступа к полю. Для всех остальных случаев оставить обычный фолбэк в геттеры-сеттеры.
Сейчас для создания одного! свойства в Java приходится писать его имя 7-12 раз, его тип 3 раза, 2-3 раза повторяющийся джавадок и в общей сложности используя 19+ слов. Это есть настоящий идиотизм.
Кроме того, я устал от классов и хочу, чтобы все было интерфейсом, и чтобы проперти можно было описывать и там.
В парадигме и есть всё как бы интерфейс. Точнее, типизированый объект, для которого список интерфейсов отслеживается виртуальной машиной, механизм описан в пункте 4. В парадигме вообще нет ничего кроме единственной конструкции со скобками. Ни классов, ни методов, ни явных интерфейсов, но объекты типизированы и морды у них вполне абстрактные. Плюс, Си образная внутренность метода, в которой уже есть и поля и прямое присваивание и прямое считывание того, что доступно для данных операций внутри этого маленького объекта. Просто, в этот метод затесались другие методы как в Паскале, ну и не local переменные можно конечно вынести в шапку. «throws» просто идентифицирует тип вызывающего метода чтобы в случае exception срезать стек даже без создания нового объекта и без выделения памяти (в случае outOfMemory смешно, да?), а в методе-обработчике этого exception об этом throw и срезаниии узнают только косвенно из аргументов, дальше — нормальное возвращение в вызывающий метод своего «класса». Этот обработчк — тоже просто метод, который принимает какие-то аргументы и сообщения.
Вот выдержка из текста обсуждения по поводу пропертей:
«Представляете, как выглядит текст такой программы? Он совершенно не похож на то, что в Delphi и Java и в C++. Он — что-то типа Лиспа, очень малое соотношение числа строчек кода к числу типов. Фактически, нижнему по иерархии классу чаще всего придётся работать с единственным полем. Поскольку, класс-метод, который уже что-то делает вразумительное, скорее всего будет внешним. В таком случае, разве, одних внутренних же методов не достаточно (без своих полей вовсе)? ».
«Больше всего памяти занимают массивы. Логика это такая вещь, которая памяти не потребляет и чем больше будет ООП, связанного с логически важными переменными, тем лучше. Это основное.
Ньюанс, мало влияющий на основное, но, всё же: в современных проектах на Java и так все поля спрятаны private и, хотя не все из них имеют геттеры и сеттеры, но, очень часто — большинство. Неявную же автогенерацию set/get легко оптимизировать простым флагом для случая отсутствия явно объявленного метода. Доступ виртуальной машины к полям класса и так не прост, это вам не доступ по адресу.»
По поводу NPE: «аbstract» модификатор полю означает NPE при попытке считать дефолтное и невозможность создать экземпляр содержащего класса без явного задания этого поля. При попытке считать ссылки на явно не инициализированные объекты — доступ к дефолтному объекту этого типа, а все примитивы обязаны либо явно инициализироваться, либо объявляться abstract.
Это лучше вашего предложения более естественным синтаксисом. Ну можно window.width = 125; выглядит понятнее, чем window.setWidth(125);
public void setAnything(Object mayBeNull) throws IllegalArgumentException {
if (mayBeNull == null) throw new IllegalArgumentException("Everything you can imagine is real (c) Pablo Picasso");
this.canNotBeNull = mayBeNull;
}
PS: причем null это еще не самое страшное. Вот классический пример из википедии
public void setHours(int hours) {
if ((hours >= 0) && (hours < 24))
this.hours = hours;
}
то есть ексепшена в будущем от использования null не будет, зато влегкую может быть нарушена бизнес логика при obj.hours = 25 или obj.hours = -12null
.В C++ для этого есть ссылки. В Kotlin — nullable классы. А в Java — да, хаос. Но не из-за properties, а из-за того, что в любую дырку можно
null
засунуть, а потом properties
. Они как раз для подобных случаев и нужны.Когда сеттер это сеттер, то после любого копипаста никаких скрытых синтаксических изменений не будет.Вот только потом возникает желание эти сеттеры наавтогенерировать и получаем «те же яйца, вид сбоку» — только ещё и хуже читабельность.
Что если я из внешнего класса скопирую во внутренний это присвоение, которое раньше было сеттером, и наоборот.А это тут вообще причём?
properties
всегда действуют.property
то у вас вызывается один и тот же код всегда.По поводу первого — так я и не спорю, мне сеттеры и проверки на null очень даже нравятся когда такие проверки нужны.
properties
не имея ни малейшего представления о том, как они работают…Второе: если я правильно помню, в дельфи остались те же самые геттеры и сеттеры. То есть мы можем реализовать изменение значения поля обьекта двумя путями, верно? Вы считаете это повышает читабельность кода?
То есть мы можем реализовать изменение значения поля обьекта двумя путями, верно?Неверно.
Вы считаете это повышает читабельность кода?Да. Именно потому что вы не можете присвоить значение полю иначе, как через
property
(даже методами внутри класса) вы можете быть уверены в том, что инварианты, связанные с этими полями всегда сохраняются.Но все же хотелось бы взглянуть на то, как это могло бы выглядеть на примере. Что то мне подсказывает, что простых красивых конструкций мы не получим.
TSomeClass=class(Tobject)
FStr: string;
FAStr: array of string;
procedure SetStr(A: string);
function GetStrByIndex(I: Integer): string;
public
PStr: string;
property AStr[I: integer]: string read GetStrByIndex;
property Str: string read FStr write SetStr;
end;
{ TSomeClass }
function TSomeClass.GetStrByIndex(I: Integer): string;
begin
Result:=FAStr[I];
end;
procedure TSomeClass.SetStr(A: string);
begin
Self.FStr:=A;
end;
Вот простой пример использования property. Что вам конкретно не понятно или смущает в этом механизме?
Поскольку, за основу я взял труп Java и final не убирал, то, в итоге, объявить final «класс-поле» и филд внутри, примитивный или опять ссылку — не проблема.
Перегружать синтаксис присваивания мне кажется неуместным тут. Это всё же методы, а внутри них — всё же настоящие присваивания своим филдам.
Просто, ваше замечание по существу было одно и первых и в такой категоричной форме, что хотелось услышать расширенный комментарий в контексте обсуждаемой темы, а не в контексте Java или Delphi. Потому что property есть не только в Delphi, да и Delphi за много лет мог поменяться, и вообще, мало ли кто и что может придумать.
Для «protected», «default» и «public» полей автогенерация сеттеров и геттеров компилятором, без автогенерации видимых сорцов, но с возможностью их перегрузки.Вы попросили возможность писать напрямую в переменные + возможность перегрузки автосгенерированных методов и на этом все. Но property это не просто перегрузка метода присвоения, это и возможность ограничить только чтение или только запись в переменную на уровне компилятора, возможность забрать/записать переменную из массива/списка по индексу.
Полный список возможностей в примере
1.Property Name : Type read Getter|nodefault;
2.Property Name : Type write Setter;
3.Property Name : Type read Getter write Setter;
4.Property Name : Type Index Constant read Getter {default : Constant|nodefault;} {stored : Boolean};
5.Property Name : Type Index Constant write Setter {default : Constant|nodefault;} {stored : Boolean};
6.Property Name : Type Index Constant read Getter write Setter {default : Constant|nodefault;} {stored : Boolean};
7.Property Name[Index : IndexType] : BaseType read Getter {default;}
8.Property Name[Index : IndexType] : BaseType write Setter; {default;}
9.Property Name[Index : IndexType] : BaseType read Getter write Setter; {default;}
10.Property Name : Type read Getter implements Interfaces...;
11.Property Name; // Повторно объявленное свойство базового класса
12.Property Name : Type; // Только Dispinterface
13.Property Name : Type readonly; // Только Dispinterface
14.Property Name : Type writeonly; // Только Dispinterface
Может быть, есть смысл как-то дополнительно информировать пользователей класса о чём-то?
Фактически, нижнему по иерархии классу чаще всего придётся работать с единственным полем.Цель какая? Сделать из Xeon'а Arduino? Вы не забываете, что одно обращение в память занимает столько же времени, сколько 300-400 арифметических операций (нет, тут нет ошибки в нулях). Ну и про потребление памяти на вот-это-вот-всё тоже не стоит забывать. А то Electron получится.
«Или я чего то не понимаю, или одно из двух», но в приведенном выше примере количество текста не меньше, нежели чем в классическом варианте getA(), setA(String A)
И как будут выглядеть проверки для сеттера и пробрасывание наверх 1...n эксепшенов?
б. Наверное, это может быть удобно для больших Ява классов тем, что дисциплинирует и не даёт возможность обходить сеттеры и геттеры, но я не хочу тут разбираться с другими парадигмами без связи с той парадигмой, которая изложена в статье.
в. Проверки абcолютно так же, как в Java, если понадобятся. Ексепшены описаны в пункте 9. Когда я статью писал, я старался думать как раз ну уровне процессора и виртуальной машины, а не просто поток мыслей выкладывал, как кому-то могло показаться.
В этом пункте самые примитивные сеттеры и геттеры я уже убрал автоматизацией с возможностью перегрузки для чего-то более сложного, тем самым, бесконечными они быть перестали.От того, что вы их не видите — они бесконечными быть не перестали. Они по-прежнему отжирают память и время исполнения (да, конечно, JIT-компилятор может с ними бороться, но во время запуска и остановки приложений — а это больное место Java вообще — всё это вылазит).
Что вы там убрали пунктом 2 — я, если честно, не понимаю, по-моему вы просто заменили хорошо видимую проблему, на ошибку в логике программы — что добром не кончается.
Когда я статью писал, я старался думать как раз ну уровне процессора и виртуальной машины, а не просто поток мыслей выкладывал, как кому-то могло показаться.Если бы вы обращали внимание на процессор и виртуальную машину — то хотя бы приблизительно прикинули сколько будут стоить все ваши «улучшения».
Если вам нужен язык в 10 раз более прожорливый по памяти и в 100-1000 раз медленнее — то таких уже есть. Много. Разных.
Ньюанс, мало влияющий на основное, но, всё же: в современных проектах на Java и так все поля спрятаны private и, хотя не все из них имеют геттеры и сеттеры, но, очень часто — большинство. Неявную же автогенерацию set/get легко оптимизировать простым флагом для случая отсутствия явно объявленного метода. Доступ виртуальной машины к полям класса и так не прост, это вам не доступ по адресу.
Т.е., ваше утверждение о прожорливости и медленности такой модели пока не доказано.
Опять же, риторика. Вы весьма невежливо сообщили, что не понимаете нечто в пункте 2, намекнув на некую логическую ошибку. Логическая ошибка это противоречие, на которое нужно указать явно, иначе непонятно, что конкретно нужно уточнять. Указать на противоречие можно помощью цитирования предположительно противоречащих друг другу утверждений собеседника — это самый простой способ. Иначе, утверждение «всё, что там написано — логическая ошибка» будет называется ложным.
«Или я чего то не понимаю, или одно из двух», но в приведенном выше примере количество текста не меньше, нежели чем в классическом варианте getA(), setA(String A)Все приведённые примеры описывают редкий случай, когда геттеры/сеттеры и/или
property
реально нужны.В случае если они не нужны — вы заводите
public
поле — и всё. Вот совсем всё.Потребуется обработка или контроль доступа — заведёте
property
. А поскольку любой, заведённый вами property
делает нетривиальную обработку — то «автогенерация сеттеров и геттеров компилятором» ну нужна. От слова совсем.Без
property
вы этого сделать не можете, так как код из «window.width = 125» в «window.setWidth(125)» автоматически не превратится.Контроль доступа потенциальный или явный нужен всегда для внешних обращений и никогда для внутренних, в случае методов. Контроль доступа к локальной переменной метода это наверное даже вообще абсурд, мне уже так хочется это называть. Пунктом 1 статьи идёт возможность возвращения более одного результата вычислений. Формально это не сделано, но фактически не-local поля в этой парадигме и выступают таковыми результатами, по совместительству с композицией.
Поэтому, ваше утверждение что "«автогенерация сеттеров и геттеров компилятором» ну нужна" кажется мне верным только если не исправлять опечатку «ну»
property Str: string read FStr write SetStr;
Отличается тем что мне еще PStr надо обязательно get и set написать итого вместо 4 я написал один, и только потому что мне нужна была проверка.
Но вся прелесть в том что при прямом доступе к переменным я могу и писать как в Java (set/get все приватное) или через доступ напрямую… или же сочетать оба подхода с помощью property.
А чем будет отличаться обработка ошибок в неявно вызываемом методе от обработки ошибок в любом другом коде?
property
диагностирует ошибку и всё, в чём проблема?P.S. По крайней мере стало понятно почему никто не хочет ничего тут всерьёз обсуждать. Когда об «революции», то есть изобретении нового языка начинает рассуждать кто-то, кто вообще кроме Java ничего не видел — это не смешно. Это грустно.
Т.е, главный вопрос, который мне неясен. Как большое количество проверок может уживаться с работой с полем изнутри родного класса? В сеттере-то много всего, не будешь же это всё каждый раз проверять, особенно если у тебя по существу вложенные методы просто, а не большие объекты со словарями полей
Exceptions по любому поводу в Грузинских банкоматах.
Ну так по дефолту же всё требуется задавать и тоже инструменты есть чтобы не дать не задавать, не говоря у же о самих NPE, которые никто не мешает создать и использовать проекту во благо. Просто, по моему опыту, 90% этих NPE от того, что забыли инициализировать какие-то дефолты.
Один из лучших способов убить любой язык программирования — выпустить новую версию, несовместимую с существующим кодом.
Кажется самое страшное, что случалось с распространёнными языками — это переход от python2 к python3.
Visual Basic (переход от классической версии к Visual Basic .NET) — это не совсем то: после ~15 лет «клинической смерти» (когда программисты, пользовавшиеся классику уже ушли, а новых ещё было мало) он снова начал набирать популярность… Но это уже другие разработчики, они решают совсем другие задачи…
Модификатор «static» из языка убрать, в качестве static — дефолтный экземпляр, доступный по ссылке на типизированный null.
Какова практическая необходимость такого изменения? Вон, люди в Kotlin наоборот плюются от отсутствия static.
Типы классов сравниваются по хеш-коду, который будет сгенерирован именами поля, именами аргументов, типами и возвращаемыми значениями,
Т.е. структурная типизация как в go и typescript вместо существующей номинативной? А зачем?
Таким образом, больше не нужен «interface» как таковой, только «class», «abstract» — лишь инструкция, запрещающая создание экземпляра
Да, но как тогда вы в методе будете указывать, что переданный параметр должен обладать такими-то свойствами? Для этого нужно будет вводить синтаксис для описания анонимного типа-структуры. А потом и тайпалиасы прибегут (что и будет аналогом интерфейсов). Я кстати ещё молчу про перфоманс instanceof/checkast. Ну и да, это не просто языковое изменение, тут JVM придётся выкинуть.
Добавление правил слияния для «extends».
Ага, т.е. множественное наследование реализаций? А как будет реализовываться vtable? Через ужасные трюки как в C++, с нескольми указателями на vtable в каждом инстансе? С неизбежным ростом размера заголовка объекта? А как при этом обеспечивать identity equality?
Динамические типы. Темплейты как в Си, а не как женериксы в Java
И как это будет работать с variance? Изобретать неявные преобразования, как в C++?
Больше не понадобятся специальные ссылки на метод, как в Java 8. Ссылка на метод будет означать ссылку на объект.
Простите, а как при ссылке на overloded-метод должен резолвиться метод с конкретной сигнатурой?
Чтобы прямо хотелось распаковать-использовать-упаковать в одном методе, а не чесалась голова «как это лучше сделать».
Практика показывает, что голова начнёт чесаться при решении задачи каскадной упаковки, а именно где остановиться и как это правило сформулировать.
Массивам нужен контроль границ только во время записи, и я бы дал возможность читать напрямую из памяти без контроля границ массива.
Чтение за границами массива — это в 99% случаев не то, чего мы реально хотели, а значит — ошибка. Одним из принципов дизайна Java является fail fast, что, исходя из моего опыта (и из чужого опыта — тоже), является благом. Проблема производительности решается в данном случае JIT-компилятором, который может сделать range analysis и доказать, что проверка не нужна. Они, конечно, слабоваты эти range-анализы, но на практике если у вас такой сложный код, что в нём сложно что-то доказать, то в нём и проверка на выход за границу массива не будет узким местом.
Какова практическая необходимость такого изменения? Вон, люди в Kotlin наоборот плюются от отсутствия static.
static не исчезает, он становится неотличим от дефолта. Вместо статичных классов и полей — объекты по умолчанию. Внутренние объекты по умолчанию, таким образом, будут как бы статичными только для себя, по отношению к своему внешнему классу, т.е., если внешний класс сам статичный и так до самого внешнего, то — статичные абсолютно.
2.
Т.е. структурная типизация как в go и typescript вместо существующей номинативной? А зачем?
Высчитывать уникальный код множества ключей vtable, это собственный тип. Ключи из сигнатур, у нас же только методы. Значение — структуры объектов композиции. Полный тип класса — хэштаблица предков и своего типа, значение — структура, описывающая наследуемый объект, см. дальше. Т.е., в обоих таблицах value это ссылки на структуры, описывающие конкретные объекты. Классов на этом уровне просто нет. Методы — адрес в этой структуре. До оптимизаций один адрес, т.к. перегружаемые методы в vtable.
3.
Да, но как тогда вы в методе будете указывать, что переданный параметр должен обладать такими-то свойствами? Для этого нужно будет вводить синтаксис для описания анонимного типа-структуры. А потом и тайпалиасы прибегут (что и будет аналогом интерфейсов). Я кстати ещё молчу про перфоманс instanceof/checkast. Ну и да, это не просто языковое изменение, тут JVM придётся выкинуть.
В языке аргумент это просто примитив либо название метода, который класс по совместительству. Там нет ничего кроме классов, они же — методы с фигурными скобками. Для машины аргумент это ссылка на структуру объекта, в которой 1: vtable, в котором хеши из сигнатур (у нас же только методы) и значение-ссылка на такую же структуру другого объекта; 2: хэштаблица из хешей (2) предков и себя самого; и 3: адрес метода. instanceof просто ищет хеш во второй таблице.
JVM — не важно, я писал о языке вообще.
4.
Ага, т.е. множественное наследование реализаций? А как будет реализовываться vtable?
Не совсем множественное наследование. vtable состоит из key — хешкода сигнатуры метода, и value — ссылки структуру, описанную в (3), где есть и тело метода и такой же vtable и т.д. до победы. Т.к. в языке нет ничего кроме методов, они же классы. Как это заполнить? В случае конфликта требовать явно указать источник, а в случае некомплекта какого-то из предков — тип убрать из списка предков (2), но часть кода повторно использовать, т.е. оставить. equality — понятно уже как?
5.
Простите, а как при ссылке на overloded-метод должен резолвиться метод с конкретной сигнатурой?
Прямо по хешу сигнатуры метода из vtable. И есть куда оптимизировать простые случаи.
6.
Практика показывает, что голова начнёт чесаться при решении задачи каскадной упаковки, а именно где остановиться и как это правило сформулировать.
Просто свои приватные массивы и примитивы, они же лежат по адресу без всяких vtable. Чужие не надо. В пункте 13 даже есть заделка, но для этого и она наверное медленная.
Чтение за границами массива — это в 99% случаев не то, чего мы реально хотели, а значит — ошибка. Одним из принципов дизайна Java является fail fast, что, исходя из моего опыта (и из чужого опыта — тоже), является благом.
Ну, это вопрос философский. Я описал именно то, что хотел бы видеть. Мусор можно и в своём массиве найти. Чтение своей памяти это первый способ рефлексии, ну а ценные данные шифровать надо.
Изобретать неявные преобразования, как в C++?
Используется обыкновенный класс с абстрактными полями, по тому же самом принципу. Можно его даже подзаполнить, если хочется. Поскольку есть динамические типы, расширяем подходящий объект этим «темлейтом» и абстрактные методы радостно становятся неабстрактными. Просто этот «темплейт» попадает в хештаблицу предков. Т.е., даже никакого механизма специального не надо. Так получается потому, что из языка всё повыкинули.
Честно говоря, ответа ни на один вопрос я не получил.
Какова практическая необходимость такого изменения? Вон, люди в Kotlin наоборот плюются от отсутствия static.
static не исчезает, он становится неотличим от дефолта. Вместо статичных классов и полей — объекты по умолчанию. Внутренние объекты по умолчанию, таким образом, будут как бы статичными только для себя, по отношению к своему внешнему классу, т.е., если внешний класс сам статичный и так до самого внешнего, то — статичные абсолютно.
Во-первых, тут вы оперируете слишком большим количеством терминов, которые мы с вами не согласовали (объекты по-умолчанию, внутренние объекты). Можете более подробно описать эти особенности дизайна вашего языка? Объекты по-умолчанию это что-то вроде object в Kotlin? Т.е. есть сущность "объект" а есть — "класс". Или всё является классом? Тогда каким образом конструируются объекты по-умолчанию для классов, у которых нет конструкторов без параметров. Во-вторых, вопрос был в том, зачем избавляться от static.
Т.е. структурная типизация как в go и typescript вместо существующей номинативной? А зачем?
На что получил что-то про особенности реализации, которые, увы, не зная всех особенностей вашего замысла, понять практически невозможно (предлагаю всё-таки для конструктивного общения описать дизайн языка, с bnf и операционной семантикой, хотя бы в очень нестрогом виде).
А вопрос-то был про то, зачем вам в языке структурная типизация вместо номинативной. В чём вы видите преимущества первой перед второй?
Да, но как тогда вы в методе будете указывать, что переданный параметр должен обладать такими-то свойствами? Для этого нужно будет вводить синтаксис для описания анонимного типа-структуры. А потом и тайпалиасы прибегут (что и будет аналогом интерфейсов).
В языке аргумент это просто примитив либо название метода, который класс по совместительству. Там нет ничего кроме классов, они же — методы с фигурными скобками. Для машины аргумент это ссылка на структуру объекта, в которой 1: vtable, в котором хеши из сигнатур (у нас же только методы) и значение-ссылка на такую же структуру другого объекта; 2: хэштаблица из хешей (2) предков и себя самого; и 3: адрес метода.
Я опять же, спрашивал не столько про особенности реализации, сколько про дизайн языка. Вот у вас, судя по всему, структурная типизация, так? Вот в typescript я могу написать
function foo(x: { bar(x: number): string }) {
x.bar(23)
}
и сюда подойдёт инстанс любого класса, у которого есть bar. Если попробовать в foo засунуть что-то не обладающее методом bar нужной сигнатуры, то компилятор нарисует ошибку. Вот где в вашем языке определяется сигнатура метода? Как в ней описать требования к передаваемому в метод объекту, если нет интерфейсов?
Ага, т.е. множественное наследование реализаций? А как будет реализовываться vtable?
Не совсем множественное наследование. vtable состоит из key — хешкода сигнатуры метода, и value — ссылки структуру, описанную в (3), где есть и тело метода и такой же vtable и т.д. до победы
А вот это уже был вопрос про реализацию. И правильно я понимаю, что вы предлагаете виртуальный вызов вместо обычной косвенной адресации со смещением (одна инструкция на x86) делать lookup в хэш-таблице? А как же производительность?
Простите, а как при ссылке на overloded-метод должен резолвиться метод с конкретной сигнатурой?
Прямо по хешу сигнатуры метода из vtable. И есть куда оптимизировать простые случаи.
Вопрос снова был про семантику а вы ответили реализацией. Хорошо, попробую вот так. Пусть у нас есть в Java такие объявления:
void foo(Integer x);
void foo(String x);
когда я пишу o.foo(23)
, компилятор точно знает, что надо вызвать первый метод, потому что он подходит по сигнатуре. Далее, если у нас все методы есть просто поля функционального типа, то такой резолв становится невозможен (например, он невозможен в JavaScript, где ровно такое поведение, и там похожая (но не такая же) штука реализуется уже в рантайме руками). Именно поэтому для ссылок на методы и в Java используется такой синтаксис, который используется (там по сигнатуре метода в целевом SAM-интерфейсе можно сделать резолв нужного метода). Вы предлагаете отказаться от перегрузки по сигнатуре? А если не предлагаете, то как разработчик должен сообщать компилятору, который из методов ему нужен?
Практика показывает, что голова начнёт чесаться при решении задачи каскадной упаковки, а именно где остановиться и как это правило сформулировать.
Просто свои приватные массивы и примитивы, они же лежат по адресу без всяких vtable. Чужие не надо. В пункте 13 даже есть заделка, но для этого и она наверное медленная.
Ещё раз обратите внимание — практика показывает. На Java вполне можно просто в виде библиотеки это сделать. И никто не делает. Точнее, делают в виде наколенных поделок, которые приходится выбрасывать, потому что при усложнении проекта и появления дополнительных требований оказывается, что никакая автоматика не справится.
Изобретать неявные преобразования, как в C++?
Используется обыкновенный класс с абстрактными полями, по тому же самом принципу. Можно его даже подзаполнить, если хочется. Поскольку есть динамические типы, расширяем подходящий объект этим «темлейтом» и абстрактные методы радостно становятся неабстрактными. Просто этот «темплейт» попадает в хештаблицу предков. Т.е., даже никакого механизма специального не надо. Так получается потому, что из языка всё повыкинули.
Вопрос был про варантность generics, т.е. про возможность объявить такое:
void foo(List<? extends C> supplier, List<? super C> consumer);
у шаблонов в C++ с этим проблемы. Ну как проблемы, там это решается средствами, которых и близко нет в Java (и про которые вы так же ничего не сказали)
Честно говоря, ответа ни на один вопрос я не получил.
судя по всему, структурная типизация, так?
Вместо описаний алгоритма вы ждали обобщающей формализации, но это лучший компромисс для меня, т.к. индукция абстракциями всегда скрадывает конкретику, а мне нужен только алгоритм. Дальше про типизацию написано много, но я выражаюсь максимально атомарно.
предлагаю всё-таки для конструктивного общения описать дизайн языка, с bnf и операционной семантикой
Это хорошо бы, но меня в первую очередь интересуют не ньюансы семантики, а алгоритм.
зачем
Вопросы «зачем» наверное могу сформулировать развёрнуто, но сейчас это не в приоритете. Из гармонии сфер с моим опытом.
1.
Во-первых, тут вы оперируете слишком большим количеством терминов, которые мы с вами не согласовали (объекты по-умолчанию, внутренние объекты).
Да, статья писалась слишком быстро.
По поводу умолчания и статики. Отвлечёмся от терминологии, описывающей языки. На диске есть данные. Данные структурированы. Иерархически, релятивно ссылками композиции и наследованием. У нас есть runtime инструмент клонирования этих данных и манипуляции ссылками. Очевидно, что на диске статично лежат дефолтные данные.
Объекты по умолчанию прямо подгружаются с диска со всеми своими внутренностями, инструмент создания нового экземпляра просто клонирует эту вложенность, начиная с того уровня, который создаётся. Дефолтные значения копируются, abstract поля перед этим либо явно назначаются, либо выдают ошибку. Таким образом, любой объект может runtime сериализоваться в исходники согласно п. 13 статьи, а не в что-то бинарное, и обратно компилироваться уже как бы в дефолтный статичный объект, который физически от остальных объектов не отличается, он отличается только своим создателем-машиной и временем происхождения. Любому объекту в памяти можно добавить поле abstract и тогда его нельзя будет клонировать без определения этого abstract и будет выдаваться NPE при попытке считать значение abstract.
2.По поводу внутренностей.
В языке за пределами тела метода нет ничего объектного кроме методов, внешних и на одном уровне. Объект, объявленный внутри другого объекта — внутренний объект. Для внешних пользователей нет даже полей, поскольку они семантически внутренние объявленные объекты, это из-за подразумеваемых неявно, до перегрузки, объектов-сеттеров и объектов-геттеров. Для самого объекта и для его внутренних, в пределах прямой видимости, поля есть, все они — приватные. Прямая видимость определяется по иерархии. Язык запрещает обращаться напрямую к полям вне прямой видимости, т.е. к полям, которые определены в других детях своих родителей.
Программа это просто область памяти, часть которой компилятор разрешает дёргать прямыми со смещением ссылками, а часть — запрещает. Эта область памяти увеличивается по мере создания новых объектов. Компилятор все вызовы в пределах прямой видимости делает прямыми со смещением, за пределами — через vtable, т.е. любой внешний вызов это не вызов из прямой видимости и происходит только через vtable. В прямой видимости также лежит либо ссылка на дескриптор объекта, либо примитив, либо массив, который я не считаю нужным делать объектом.
3.Что называть классом объекта? Весь дескриптор, описанный в предыдущих ответах. Т.е., у каждого объекта кроме наследников ещё и два собственных типа. Первый высчитывается просто по сигнатуре метода. Второй — хеш всех сигнатур из vtable. Кто как назовёт эту типизацию?
Алгоритм я постарался описать подробно и работает он за конечное время, об этом алгоритме ещё раз в след параграфе про вызов метода.
Дальше Баньян, наследующий ни кого-нибудь, а аж собственные внутренние классы. В дескрипторе в первой таблице по хэшам сигнатур значениями дескрипторы Tree, Branch, Leaf, Cell и перегруженный Grow, и хэш-ключ типа из всех этих сигнатур. Во второй таблице, по своим ключам типа, дескрипторы самого Banyan и его предков Tree, Branch, Leaf и Cell. Так у него срослось.
void Banyan extends Banyan.Tree{
void Tree() extends Tree.Branch{
void Branch() extends Branch.Leaf{
void Leaf extends Leaf.Cell{
Cell[] cells; //тут массивы - не объекты
void Cell(){
void Grow(){
}
}//Из этой клетки пошло деление-заполнение массива, она дефолтная и в массив её не обязательно.
@Override
void Grow(){
}
};//Эта клетка произошла от зелёных клеток ростка, но решила быть веткой
@Override
void Grow(){
}
}//Первый Branch это ствол.
@Override
void Grow(){
}
}//Это старейший баян
@Override
void Grow(){
}
}
4.Собственные типы могут совпадать, если совпадает ещё и хэш ключей vtable, то это либо просто клоны, не перезагружавшие общего предка, либо, другая крайность, счастливо совпавшие и не имеющие общих предков классы из разных реализаций. Могут они быть взаимонезаменяемыми? Вопрос архитектору, факт совпадения можно выяснить на любом этапе даже runtime, поскольку ссылки-значения отличаются частично или полностью.
5.
обладающее методом bar нужной сигнатуры, то компилятор нарисует ошибку. Вот где в вашем языке определяется сигнатура метода? Как в ней описать требования к передаваемому в метод объекту, если нет интерфейсов?
Описание на уровне языка выглядит точно так, как описание в Яве. Fruit first. При компиляции исходников, структура передаваемого в метод объекта бёрется из двух таблиц просто по Fruit. Первая собственная таблица компилятора — имена->сигнатуры. Вторая — сигнатуры->ссылки на структуры. Тип, интерфейс и класс и даже метод — «Fruit». Посредством этих двух таблиц мы получаем ссылку на нужную структуру и вперёд.
Вы предлагаете отказаться от перегрузки по сигнатуре?
Во-первых, это проблема только компилятора, которая разрешима, см. дальше, но лаконичнее всего конечно не перегружать, а обернуть.
void Foo(int x){
void Foo(char* x){
}
}
потому что базовая функциональность там скорее всего в int x, a текст в него конвертируется, либо наоборот, это по смыслу. Если же там вообще разная функциональность, то я считаю такую перегрузку вредной.
При необходимости выбирать метод нужно всего-то положить в первую таблицу компилятора (не дескриптора) не сигнатуру, а таблицу сигнатур, из которых выбрать, причём, это же только при компиляции.
Чтот такое Fruit? Фрукт. Как кто-то назовёт тип этого типа?
6. Машина посылает аргументом либо примитив, либо прямую ссылку на структуру в памяти. Поскольку, при вызове метода мы уже подготовили ссылки на дескрипторы, либо из собственного дескриптора с vtable, либо приватные по смещению, либо локальные после операций с первыми двумя и аргументами. По этой ссылке на дескриптор будет всё найдено в вызываемом методе.
7.
А вот это уже был вопрос про реализацию. И правильно я понимаю, что вы предлагаете виртуальный вызов вместо обычной косвенной адресации со смещением (одна инструкция на x86) делать lookup в хэш-таблице? А как же производительность?
Так обыгрываютя только логически важные переменные. Чем больше будет ООП, вокруг таких переменных — тем лучше. Не случайно к проектам на Си в довесок идут всякие медленные скриптяги.
Производительность компенсируется тем, что работа с родными полями и полями прямой видимости происходит напрямую. Элементарные массивы я не стал бы делать объектами, ну и проверки границ при доступе убрал бы.
Простейший процедурный код там, где нужна производительность, компилятор может многое оптимизировать, если не будет внешних ссылок. Можно добавить модификатор private, который будет явно сообщать, что не local, но полное внешнее исчезновение.
Вопрос был про варантность generics, т.е. про возможность объявить такое:
Да, без специального синтаксиса для темплейтов будет уныло вбивать. Утилита даже и runtime создаст два новых объекта:
void Supplier extends List{
//в котором перезагрузит все методы с Object, например Object Get(int index) на
С Get(int index) extends Get(int){
return (C)super.Get(index);
}
<...>
}
//и ещё один
void Consumer extends List{
Object Add(Object arg) extends Add(Object) throws TheObjectNotParentFor{
if (! C.instanceOf(arg)){ //С это полноправный объект и arg - полноправный класс
throw TheObjectNotParentFor(object, C);//catch сделано через методы, в статье описано в пункте 9
}
return super.Add(object);
}
<...>
}
Объявляем void foo(List<? extends C> supplier, List<? super C> consumer);
Ещё раз обратите внимание — практика показывает. На Java вполне можно просто в виде библиотеки это сделать. И никто не делает. Точнее, делают в виде наколенных поделок, которые приходится
Java — слишком сложный язык. Там слишком много лишнего. Тут же нет ничего. Процедурные сорцы просто повторно использовать, генерить на диск не надо. Либо наслаждаться их отсутствием, назвав нативным кодом, что тоже весьма и весьма не плохо.
п15. Чтоб можно было грабить корованы.
Очень наивные утверждения, ломающие обратную совместимость, либо рудиментарные, либо вообще не реализуемые ввиду возникающих побочных проблем. Из здравого я бы отметил только п.3 — properties. Легко реализуемо и сразу убирает огромное количество бойлерплейта.
properties
не годятся.P. S. Мне не надо рассказывать, что это. Я отлично знаю, и в целом согласен, что появление Delphi-style property в Java пойдет ей на пользу.
Непонятность это конечно вина статьи, потому что подобные вещи не пишутся наверное в спешке, но тема специальная, для ценителей и смысла нет писать бессодержательные негативные комментарии, если просто тупо не разбирался. Желания разобраться не было, так как наводящих вопросов был ровным счётом один от товарища джависта в конце обсуждения. Народ просто гнал какую-то свою дельфийскую волну непонятно куда непонятно зачем.
Никакого труда не составляло бы за всё это время по пунктам перечислить конкретные наивности и побочные проблемы, но их там просто нет или исчезающе мало.
Мой коммент выше читали? Там как раз некоторые наивности разобраны и обозначены некоторые побочные проблемы.
Просто чтобы понять суть многих проблем, посмотрите обсуждения, которые велись в блоге Kotlin, когда он еще был на этапе дизайна. Там тоже предлагали многообещающие нововведения, от большинства которых впоследствии пришлось отказаться, например от функции с множественным результатом. Некоторые из них все же были реализованы, но совсем в другом виде.
[del]
Возможность вернуть более одного результата из функции.
Это не удобно. Лучше возвращать структуру (частный случай — кортеж), а с ней уже делать что душе угодно. А не как в Го — примите и проигнорируйте.
Для «protected», «default» и «public» полей автогенерация сеттеров и геттеров компилятором, без автогенерации видимых сорцов, но с возможностью их перегрузки, «private» убрать из языка, поскольку «сами» поля все и так будут «private» без возможности перегрузки.
Фактически вы описали property.
Типы классов сравниваются по хеш-коду, который будет сгенерирован именами поля, именами аргументов, типами и возвращаемыми значениями
Фактически вы описали структурную типизацию.
В результате, объект будет наследовать код и реализовывать все родительские типы.
Фактически вы описали множественное наследование.
не сложно организовать перепланировку расширением типа инстанса прямо runtime, сужение — запретить
Насколько я понял речь про ковариантность. А что насчёт контравариантности и инвариантности?
Подметоды как в Паскале.
Все, конечно, в курсое как там в Паскале. Замыкания что ли?
Конструктор класса будет телом метода по умолчанию, который будет создан во время компиляции, в соответствии с пунктом 2 «экземпляры по умолчанию». Больше не понадобятся специальные ссылки на метод, как в Java 8. Ссылка на метод будет означать ссылку на объект.
По описанию похоже на замыкания.
Новый оператор для runtime шифрования всяких примитивов
Какой алгоритм и размер ключа захардкодим?
я бы дал возможность читать напрямую из памяти без контроля границ массива
То есть иногда читать мусор из других объектов, а иногда аварийно завершаться по access violation?
Кроме того, в методе «run» объекта Runnable, который передается в Thread, требовать явно вызывать метод, прерывающий поток, и, чтобы без этого была ошибка компиляции.
Какой поток? Зачем его прерывать? Речь о yield что ли?
Фактически, граф всех объектов в памяти всегда имеет только примитивные типы, массивы или null или ссылку на нечто нативное на всех своих вершинах. Будет очень полезен базовый инструмент, который может сохранять весь этот граф в любой текстовой форме.
И как сохранить часть этого графа? Если же предлагается сохранять его целиком, то проще и быстрее память сдампить, как это делается в SmallTalk.
Полезный инструмент для поиска любых объектов в графе объектов по заданным критериям с учетом модификаторов доступа, по типу простого SQL.
Если это будет не только лишь дерево, а именно произвольный граф, то боюсь ваш SQL получится очень не простым.
Резюмируя: без примеров хотя бы псевдокода понять о чём вы говорите крайне сложно. А вообще, заходите к нам в телеграм, где мы иногда обсуждаем дизайн языков: https://t.me/lang_idioms
Это не удобно. Лучше возвращать структуру (частный случай — кортеж), а с ней уже делать что душе угодно.С какой точки зрения неудобно? Когда мне нужны просто int x, y, то мне всегда хочется написать int x, y = func();
int int func(){ return x, y; } чем что-то создавать, даже структуру.
Фактически вы описали property.Может быть, но особенность изложенной мной модели в том, что в ней это и многое фигурирует неявно, без дополнительной поддержки.
Фактически вы описали структурную типизацию.Может быть, но я не находил однозначного ответа в рамках доступных определений. Чуть выше, 7-го и 8-го числа, описал дескрипитор и набросал алгоритм.
Фактически вы описали множественное наследование.
Может быть, но существующие алгоритмы, для которых применим этот термин, наверняка работают не так, как описанный мной.
Насколько я понял речь про ковариантность. А что насчёт контравариантности и инвариантности?Выше, 8-го числа, я описал алгоритм, по которому утилита должна поддерживать семантику void foo(List<? extends C> supplier, List<? super C> consumer); Хотя, это будет работать с некоторыми интересными ньюансами, потому что в дескрипторе не отражена иерахия наследования, а отражены только сами факты наследования. Иерархию можно при желании отследить, но, пока я не вижу безальтернативной необходимости её хранить, если вы видите — можете привести пример.
По описанию похоже на замыкания.Подобных вроде похожестей тут слишком много, иначе я не стал бы писать статью, если бы существующие языки меня устраивали. Сейчас все языки как будто из одного конструктора, не находите?
Какой алгоритм и размер ключа захардкодим?По самому минимуму для собственных примитивных массивов хватит. Не хочу портить свою и так ужасную репутацию грустными воспоминаниями о том безобразии, которое я встречал в реальных работающих проектах. У людей нет времени ни на что.
То есть иногда читать мусор из других объектов, а иногда аварийно завершаться по access violation?Видимо, вместо этого пункта должно быть то, что это не язык в себе, а фреймворк ООП для процедурных языков. Какой там будет процедурный язык мне не важно, но предыдущий пункт фреймворком бы поддержал.
Какой поток? Зачем его прерывать? Речь о yield что ли?Дело в том, что рабочий день не должен быть бесконечным даже у кремниевых организмов.
Потоку нужно не только поспать, но ещё и заняться насущными делами, типа принять-отправить message, выполнить возникшие из других потоков дела в Runnable, ну и вообще сменить обстановку, развеяться, во избежание появления всяких ненужных блокировок потоков энергии.
И как сохранить часть этого графа?Почему часть, если у меня написано «весь», я это делал, хотя и часть — не неразрешимая проблема.
Если это будет не только лишь дерево, а именно произвольный граф, то боюсь ваш SQL получится очень не простым.У меня наоборот получался слишком простой, но не полноценный, хотя, может быть, у меня на полноценный просто времени не было. Вообще, стремиться нужно к возможностям экспертной системы, а куда стремиться-то в этой жизни?
Резюмируя: без примеров хотя бы псевдокода понять о чём вы говорите крайне сложно.Там выше «баян баньян» есть, это и будет рабочим названием.
А вообще, заходите к нам в телеграм, где мы иногда обсуждаем дизайн языков: t.me/lang_idiomsСпасибо, зайду
Насколько я понял речь про ковариантность. А что насчёт контравариантности и инвариантности?
В дескрипторе за инвариантность отвечает тип2, хэш всех сигнатур из таблицы сигнатуры->дескрипторы. Нужный интерфейс может появиться в результате слияния любых дескрипторов по любому правилу, какое пожелает программист, это стоит как-то регулировать? Все предки во второй таблице тип2 -> дескриптор. Ньюанс пока вижу лишь неинтересный, в том, что super-у нужно явно указать предка, если предков больше, чем один, а если предок на этапе компиляции один, то компилятор укажет сам. Что там ещё может быть пока не соображу.
Ява после извержения вулкана