Pull to refresh

Comments 88

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

> Было бы прекрасно, если бы исходные коды (по факту логика) были бы как можно больше независимы от архитектуры железа.

Выглядит противоречиво. либо обеспечивается как можно большая абстракция от железа, либо видно каждый бит. Либо можно обеспечить оба этих требования ценой производительности, спрятав всё в виртуальную машину. Хотя нет, это отказ от первого
Самая острая проблема публикации в том, что архитектурные и, в общем-то, философские проблемы о способах и порядке разработки архитектуры приложения пытаются решить чисто инструментальными средствами. Итог немного предсказуем.

P.S. А пробовали "me." заменить на "I."? Может, будет ещё прирост?

Надо на просто точку заметь! "." быстрее чем "i."

Плюсую за интерес к весёлым темам!
На мой взгляд «I.», i-метод и просто точка не подходят по причине уставшего взгляда программиста. Кто долго засиживается с кодом просто не увидит эту точку.
За me, как и за this, глаза цепляются лучше.

Вот так намного заметнее будет
⬤getValue

использование геттеров не очень хороший метод. Например, в с++ для доступа к закрытым данным-членам визуально удобнее использовать метод с именем члена. При этом имя члена содержит либо префикс, либо суффикс. Выглядит это? например, следующим образом
class T {
int @rows;
int @cols;
public:

int rows() {return @rows;}
int cols() {return @cols;}

}

Не очень хороший визуально или логически? Если вам нужно менять свойство, есть, фактически, два способа. Делать свойство публичным (и не иметь потом простой возможности перехватить изменения) или делать геттер+сеттер.

Речь шла о том, так ли необходимы геттеры.
Насчет сеттеров — другая ситуация. В подавляющем большинстве случаев защищенные данные могут модифицироваться собственными методами класса, нагруженными основным функционалом. Например, при моделировании, скажем, эволюции некоторого объекта, его состояние вполне может изменять тот метод или друг, который его, собственно, и рассчитывает. Необходимость в каких либо сеттерах в таких случаях отсутствует. Ну и, собственно, почему именно get(), а не clone(), например? set(), а не put()? Вообще get() в естественном языке предполагает перемещение, а не клонирование.

Если речь непосредственно про то, писать ли "getValue", "value" или "cloneValue" — то я просто пользуюсь соглашениями. В питоне пользуются паблик-свойствами вместо геттеров/сеттеров (потому что можно декоратор @property навесить), а в java или php код с cloneValue просто не пройдет ревью.


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

Потому в ряде рекомендаций по форматированию поля имеют префикс, а геттер его не имеет. Так доступ к полю получается более интуитивным.

А вообще, это дикий оффтоп. Язык не должен указывать, как назвать тот или иной метод. Это не его работа. Язык должен позволять получать копию, неизменяемую и изменяемую ссылку, адрес, монопольное, разделяемое право владения и Страуструп знает что ещё. А как должен называться конкретный метод получения — не его собачье дело. Не ему, в итоге, писать исходники.
однако будет лучше, если написанный на ЯП код будет соответствовать тем же гайдлайнам, в рамках которого разрабатывается стандартная библиотека этого языка.
Так доступ к полю получается более интуитивным.

Горизонтальная палка делает доступ более интимным. :-)

или голая стрелка, если речь идет об указателе, для которого возможна арифметика. Кстати, стрелка не будет выпадать из «уставшего взгляда».
Ага, я так надеялся увидеть новую абстракцию «наборы», а тут полстатьи про то чем «me» лучше «this». В итоге автор убрал два символа из в общем-то нечасто используемого символа, зато навалил фигурных скобок вместо отступов. Хотя это всё имеет мало отношения к читаемости языка. Плюсы сложнее питона не из-за фигурных скобок.

В принципе нет особой проблемы сделать и быстро и абстрактно и видеть каждый бит. Просто придётся написать кучу дополнительного архитектурно-специфичного оптимального кода в компиляторе :-)

Спасибо за интерес!
В статье я пояснил и по сути привёл пример, что мы стремимся к прозрачности кода (текущей нам не всегда достаточно), но не возводим её в абсолют. Независимость/абстракция от железа более важна — на неё спрос выше.
Сейчас есть проблемы, встроенные типы данных для Вас чёрный ящик, за который можно переступать только в ассемблер. И если тип содержит сложную архитектуру или введены спец. состояния (такие как Null, NaN), в случае проблемы Вы пускаетесь в исследования этой скрытой структуры или поиски документации от разработчика компилятора или человека, уже исследовавшего этот механизм. Архитектура таких типов имеет абстракцию над железом, но увидеть её Вы не можете. Моё предложение (выкинуть чёрные ящики и) описать эти абстракции в коде.
В результате переход от высокоуровнего кода до ассемблерных команд конкретного железа будет сглажен. Эти структуры станут задокументированы в коде (по сути будут прозрачны в высокоуровневом коде). Увеличится понимание устройства типов и протекающих с ними процессов.
Вы пытаетесь скрестить ежа (системный уровень) и ужа (прикладной уровень). Как в старом анекдоте, получится 2 метра колючей проволоки, которой вы отгородите свой синтаксис от любых посягательств на его использование.
встроенные типы данных для Вас чёрный ящик
Перед вами две архитектуры: на одной биты копчёные, на другой триты кипячёные. Какую себе возьмёте, за какую тимлида посадите?
Вы пытаетесь скрестить ежа (системный уровень) и ужа (прикладной уровень).

Вы же не хотите сказать, что С++ плохой язык и такой же как Вы описали выше?
Если нет, то совершенно не понятно почему Вы против ΣL?

Перед вами две архитектуры: на одной биты копчёные, на другой триты кипячёные. Какую себе возьмёте, за какую тимлида посадите?

Это не проблема языка, это проблема людей — микроскопом тоже гвозди можно забивать.

Да даже, если и возникла беда в организации у людей, то среда разработки объединяя код сможет сгладить этот конфликт. Теоретически возможно, практически пока не реализовано.
Вы же не хотите сказать, что С++ плохой язык и такой же как Вы описали выше?
Он особенный. С архитектурной точки зрения он ужасен: не даром уже дцать лет подряд выходят его убийцы. Но у него есть фишка, которой нет у других, и которая ещё долго будет держать плюсы сверху. Огромная кодовая база, своя и унаследованная от Си, и потрясающая гибкость. Вот и получается, что дозволено Юпитеру, не дозволено быку.
Это не проблема языка, это проблема людей — микроскопом тоже гвозди можно забивать.
Нет, это ваша проблема, потому как вы создаёте инструмент. И это была ваша заявка «сделать инструмент для всего».
Да даже, если и возникла беда в организации у людей, то среда разработки объединяя код сможет сгладить этот конфликт. Теоретически возможно, практически пока не реализовано.
Тогда зачем бросать привычные инструменты, если ваш не лучше? Извините, но платформу я могу и по
#if defined(__LP64__) || defined(_M_IA64)
цеплять, лишние 10 символов не критичны. А вот что будет на выходе вашей сигмы — это уже большой вопрос.
Я считаю, что код должен минимально отличаться от литературного текста, так как код — это не программа, но лишь документация для компилятора. Поэтому me — крайне плохое решение: оно не вяжется с английским языком.
> This value is one — привычно, но не совсем понятно
> Me value is one — просто криво
> My value is one — звучит гладко

И да: как писали выше, основная проблема современных языков — архитектура, а не синтаксис. С последним мы кое-как разобрались, в конце концов, всегда можно разработать своё подмножество языка, транслирующееся в оригинал. Если уж так хочется заменить this)

А вот как связать обработку данных с архитектурой ясно не до конца. Или как запретить дублирование кода на уровня языка.
А можно поподробнее про разработку подмножества языка?

Please, get value of property Money from object MyObject and add to variable Total :)

Странное впечатление
Конечно троичная логика это не проблема вообще, просто потому что в реальном мире железок с троичной логикой нет; а если кто и осилит создание троичного микропроцессора, то уж разработать модификацию Си для него точно сможет.
Ну и проблема ключевого слова «this/self/me» это тем более не проблема. Я сам разрабатываю язык программирования, с гораздо более высоким уровнем детализации в исследовательском процессе (сейчас получается довольно объемная книга с подробнейшим рассмотрением различных возможностей и решений в различных языках программирования, их сравнением, выбором оптимальных решений и разработкой собственных оригинальных возможностей с нуля). Я задумывался в том числе и над эстетичесими вопросами, и кажется что оптимальная длина ключевых слов 2..5 символов, когда длинее 6 это уже некомфортно. Разница между 4 и 2 для редкоиспользуемых слов (таких как this) несущественна.

Я вот тоже свой язык разрабатываю. Может мы как-то скооперируемся в какому-нибудь телеграм-чате, например, где вбрасывали бы идеи и обсуждали те, кому эта тема интересна?

_ — это множество целых беззнаковых чисел,
__ — множество целых знаковых чисел,
__._ — знаковое, с фиксированной точкой
__,_ — знаковое, с плавающий точкой
_._ — беззнаковое, с фиксированной точкой
_,_ — беззнаковое с плавающей точкой


Разрешите догадку, у вас отличное (ну или не очень плохое) зрение :)
ИМХО, нечитабельно.
Верно, но я предполагаю, что Вы не будете использовать эти базовые конструкции повседневно. Для любого языка существуют правила хорошего тона в оформлении кода.
Этот инструмент в первую очередь для тех, кто создаёт привычные для Вас типы (такие как byte, int, short). К тому же в языке есть алиасы, Вы сможете его гибко подстроить под себя.
Почти все современные языки не используют такие возможности, так как их основа другая и не всегда это позволяет, а числа предоставлены компилятору.

Лучше уж знакоместа обозначать решёткой:


#### — это множество целых беззнаковых чисел (число решёток — максимальное число разрядов)
?#### — множество целых знаковых чисел (число решёток — максимальное число разрядов)
?##.## — знаковое, с фиксированной точкой (число решёток — максимальное число разрядов)
?#.###e## — знаковое, с плавающий точкой
##.## — беззнаковое, с фиксированной точкой (число решёток — максимальное число разрядов)
#.###e## — беззнаковое с плавающей точкой (число решёток — максимальное число разрядов)

Мысль определённо правильная, хорошая.
В мой язык она из-за поддержки разных архитектур неочень подходит, но я подумаю. В первую очередь решётка лучше различима, чем подчёркивание.
Спасибо за комментарий и активный интерес к разработке языков (раз уж тема поспособствовала чат создать)!

А можно поподробнее про вещественную арифметику в вашем языке?

Можно и нужно. Не обещаю, что скоро, но напишу в отдельном посте.

Вы предполагаете, будет удобно каждый раз лезть во внутренности устройства типа Byte вместо того, что бы просто запомнить, как оно там по документации? В чем вообще идея самодокументирующихся базовых типов?

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

Да, это редко нужно. Об этом не хотят говорить, что я отметил в статье.

Видимо Вы не сталкивались с упомянутыми проблемами. Сейчас не найду подходящего примера, но как пример рекомендую послушать это с 16:50. Миф документации чуточку развеется.
Идея в том, чтобы Вы смогли заглянуть ниже (в момент, когда будет интересно или когда понадобится) и понять это устройство, даже если документации нет

Идея хороша, но магический компилятор сводит ее на нет. Мы смотрим на me.state := someState, и у нас нет никакого способа понять, какие же операции на самом деле происходят.

Когда базовый тип ведёт себя настолько непонятно, что документации не хватает и нужно лезть в код, как он там устроен? Нет, не сталкивался, а вы?


Вот у вас используется слово state. Где оно определено? С ним намного больше будет проблем, чем с байтом или boolean. Или только в компиляторе смотреть, что же это слово на самом деле делает?

Я не совсем программист, K&R на стройке нашёл, но…
В начале работы на программой у нас в голове есть абстрация предметной области и абстракция исполняющего устройства, наша задача заполнить разрыв между этими двумя границами; если быть более точным, то абстракции абстракций: чтобы иметь собственные модели надо 5 лет отработать по профессии, а потом еще лет 5 разрабатывать процессоры с обвязкой.

Чем более подробны эти абстракции, тем дороже программист, а это заказчику нафиг не надо. Программисты это понимают и строят слои абстракций, дальше которых не лезут в 99% случаев. Если мы абстрагируемся от предметной области, то программа не закрывает потребностей заказчика, и он не даёт денег. Плохо. Значит, пытаемся отдалиться от железа; для начинающего пышника или JSника компьютер может быть вообще волшебный коробкой, но его тривиальный код таки будет работать, благодаря программистам, тоже не волшебникам, но у которых другой продукт и следовательно сдвинутый, но не более широкий, диапазон абстракций

Чтобы разменять дорогого программиста на много дешёвых, между кодером и клиентам стоят аналитики и тим-/техлиды, а между кодером и железом — сисадмины и тестировщики. А язык… От него достаточно быть понятным, однозначным и бьющим по рукам в рамках своих абстракций, а за границами языка — обращайтесь к другим программистам, чтобы они написали вам инструмент: анализатор или компилятор. Или к тестировщикам, чтобы полезли в дампы памяти и сказали, в чем затык.
Как уже написали me, my и i — это «кто», т.е. одушевленное.
Логичнее:
it — “это”, перекликается со «штукой» ( ‘item’ ) и с итерацией;

можно использовать артикли типа ‘a’ и ‘the’,
если развивать дальше то ‘the’ === ‘z’
получаем пару:
‘A’ — нечто неопределенное,
‘Z’ — нечто определенное.

диапазон A <—> Z и т.п.
заглавными даже будет более визуально определимо, да и набирать удобно, обе рядом с левым шифтом )
Пару лет назад, тоже были идеи по созданию нового языка программирования. Так и осталось на уровне концепта github.com/sms-system/Programming-Language-Concept. Увидел схожий момент с символом @ — который использовал для обозначения неймспейсов. Заменой слову `this`, я в свое время выбрал `it`
Итак, ниже я отобрал 5 самых «ненужных и бесполезных» пунктов, о которых «никто не говорит», а я расскажу.

Как ваш язык решает описанные вами же проблемы?


Каким человекочитаемым и коротким ключевым словом можно заменить современное this, чтобы не исказить его смысл? [...] Мне же в голову приходит два перспективных варианта: очень короткое i и более длинное me.

С одной стороны, замена this на me, очевидно, меняет смысл — это разная семанткика (хотя, надо заметить, что в каком-то VB использовалось именно Me для обращения к текущей форме).


Но с другой стороны надо заметить, что вы просто боретесь с ненужной мельницей...


В последующие секунды скорость набора me значительно опережала this и self.
выражение me.valueResult += me.valueOne * me.valueTwo; в момент печати читалось словно me нет совсем

Вы не поверите, но самое простое решение — это не писать this (или me) вообще. Есть языки, которые это позволяют, почему бы вам просто не последовать их примеру?

Есть языки, которые это позволяют, почему бы вам просто не последовать их примеру?

И в таких языках появляются нотации вида mName, чтобы не путать их с локальными переменными вида name.

Да. Но такая нотация все равно короче, чем [любой идентификатор].name.

Ещё короче — именовать поля объекта с большой буквы, а локальные переменные с маленькой.

Так тоже можно (собственно, так и делают), но теряется возможность различать поля и свойства объекта. Другое дело, что не всегда эта возможность нужна...

Основой языка «Сигма» являются наборы, которые объединяют в себе большинство существующих парадигм программирования. Наборы значительно более мощный и гибкий инструмент, чем объекты. Наборы были с программистами всегда и в каждом языке программирования до этого. Массив это набор однотипных элементов. Функция это набор инструкций. Структуры/записи это набор полей данных. Класс/объект это набор из полей данных и методов-функций. Пространства имён в модулях это тоже наборы, которые содержат в себе всю эту начинку: функции, классы и т.д. Наборы подобно мат. множествам могут объединяться и обладают рядом свойств.

А, да, кстати. Можно, пожалуйста, услышать определение понятия "набор", которое вы используете в этом абзаце, и какими именно свойствами "набор" обладает?


Базовый набор носит классическое название source, от него наследуются все остальные наборы.

Что вы вкладываете в понятие "наследуются"?

Набор — это совокупность элементов. Будет вернее сказать, что набор — это интерфейс для совокупности элементов. Елементами является всё вышеперечисленное в приведённой Вами цитате.

Внутреннее устройство набора по факту является математическим множеством. За исключением некоторых нюансов (описания не для комментария), набор обладает свойствами множества. Или, если будет понятнее, набор является контейнером элементов. Описание набора визуально напоминает классы. Отсюда возможность применить термин «наследование». Наследованием является включение совокупности элементов в новый набор. Множественное наследование это объединение наборов.

P.S. Множества есть во всех языках, но как контейнеры на уровне классов и объектов они не использовались. По крайней мере в популярных языках, я такого не наблюдал.
Будет вернее сказать, что набор — это интерфейс для совокупности элементов.

Что значит слово "интерфейс" в этом предложении?


Внутреннее устройство набора по факту является математическим множеством.

Считайте, что я ничего не знаю про математические множества. Что же такое "набор"?


Или, если будет понятнее, набор является контейнером элементов.

Элементы в наборе упорядочены или нет? Один и тот же элемент может быть дважды или нет — и если нет, то как определяется, что элемент "один и тот же"? Тип элементов набора ограничен? Тип самого набора определен?


Множественное наследование это объединение наборов.

Если вы объединяете два набора в которых есть "один и тот же" элемент, что происходит?


Множества есть во всех языках, но как контейнеры на уровне классов и объектов они не использовались.

А зачем? Какую задачу это выполняет?

Будет понятнее, если вы не будете предлагать три разных определения в одном комментарии. То "набор" напоминает массив, то интерфейс, то объект (итерируемый, видимо).

Множества есть во всех языках, но как контейнеры на уровне классов и объектов они не использовались.

В PHP объекты примерно так и устроены.

Обратите внимание на описание значения бита и его состояния.

А что такое "состояние", что оно заслужило отдельного ключевого слова state, и как это используется на практике потребителем класса?

Состояние это очень важно: установлена ли у Вас галочка True или нет False. Разные типы имеют разные состояния (так принято в современном программировании), и не всегда True это отдельный булев тип, когда-то он целое число строго = 1, а когда-то любое целое >= 0. Сначало с этим были ошибки, сейчас программисты привыкли использовать такое знание как хаки в разработке.
Благодаря этому
что такое «состояние», что оно заслужило отдельного ключевого слова state
упрощается описание РБНФ. Добавление одного «state» убрало из языка ряд ключевых слов, таких как: float, int, byte, bool, true, false и т.д.

Вот только вы так и не объяснили, чт оже такое "состояние" для типа.


установлена ли у Вас галочка True или нет False.
… это — состояние галочки.

Разные типы имеют разные состояния (так принято в современном программировании)
Я не встречал "в современном программировании" понятия "состояние" у типов — только у объектов. А у типов обычно есть допустимое множество объектов. Вы о нем сейчас говорите?

Добавление одного «state» убрало из языка ряд ключевых слов, таких как: float, int, byte, bool, true, false и т.д.
Ээээ… нет.

float, int, byte, bool — это названия (а в некоторых языках — и вовсе алиасы) встроенных типов. У вас они тоже есть (тип bit вы создаете в примере, про остальные пишете в комментариях).


true и false — это, в зависимости от реализации, либо литералы (если есть специальный тип bool), либо константы. И они у вас тоже есть.


Все-таки, будет лучше, если вы покажете на примере, как эти "состояния типа" используются в коде. Не определяются, а именно используются.

Там в середине сбилось форматирование, читать так:


установлена ли у Вас галочка True или нет False.

… это — состояние галочки.


Разные типы имеют разные состояния (так принято в современном программировании)

Я не встречал "в современном программировании" понятия "состояние" у типов — только у объектов. А у типов обычно есть допустимое множество объектов. Вы о нем сейчас говорите?


Добавление одного «state» убрало из языка ряд ключевых слов, таких как: float, int, byte, bool, true, false и т.д.

Ээээ… нет.


(далее по тексту)

Нет, это не состояние галочки.
Если в «Сигма» Вы подключите к своему проекту только decimal модуль, то Вы не найдёте у меня True и False. Сам язык о них ничего не знает, он работает с числами и множествами. Состояния для привычки, удобства и по тому, что они нужны людям.

Подробнее о состоянии с примером Вы найдёте в статье.
Если в «Сигма» Вы подключите к своему проекту только decimal модуль, то Вы не найдёте у меня True и False.

Ну то есть это такие очень странные константы. Термин "состояние" здесь некорректен.


Так как же это работает? В той части, где "Состояние — это зафиксированная совокупность определённых элементов из набора, его статическое подмножество."? Предположим, у вас есть тип, описывающий рациональную дробь с числителем и знаменателем, и "состояние" Invalid, где знаменатель равен нулю. Как конкретно работают


  • проверка smth is Invalid
  • присвоение smth := Invalid
Давайте накидаем Ваш пример:
smth {
   int Numerator;   //числитель
   int Denominator; //знаменатель
   state Invalid is { //Ваше состояние
      me.denominator == 0;
   }
   init() { //конструктор без параметров
      me.Numerator := 0;
      me.Denominator := 0;
   }
   operator.right := (state s){ //более верно писать: smth.state s
      me.state := s; //присвоение состояния претерпит изменения в следующей версии, но пока так можно
   }
}


smth s;
if (smth is Invalid) { smth := Invalid; }

//в оптимизированном коде это превратиться в привычное:
if (smth.denominator == 0) { smth.denominator := 0; }

Другие более сложные моменты так же будут оптимизированы компилятором в простые asm-коды под целевую платформу.

Без оптимизации хранится набор статичных значений(элементов) справа. В нашем примере это 0. В момент работы с состоянием формируется активный набор из указанных слева значений. В нашем случае в такой набор попадёт значение me.denominator, у нас оно было проинициализировано 0-ём. При выполнении оператора is произойдёт вычитание из активного набора статичного набора по правилам математического множества (тождественные элементы исчезнут из активного набора). Условный оператор проверит получилось ли пустое множество или нет. Если получилось, выполнит код инструкций в фигурных скобках.
Присвоение определяется пользователем, кроме случая для набора — содержимое которого пропадает, а новая совокупность элементов связывается с именем этого набора. При стандартной реализации присвоения это и происходит. Наборам левой части (из описания состояния) присваивается значение статического набора (из правой части).
При выполнении оператора is произойдёт вычитание из активного набора статичного набора по правилам математического множества (тождественные элементы исчезнут из активного набора).

Как проверяется тождественность? (собственно, я уже задавал вам этот вопрос)


Присвоение определяется пользователем

А каким чудом me.state := s превратилось в me.denominator := 0? Какая волшебная логика распарсит сложное состояние (с несколькими логическими ветвлениями) и превратит его в присвоения?

Наборы тождественны, если состоят из одинаковых элементов.

Очевидно, что вложенные наборы сравниваются так же, путём вычитания. Речь об элементах, являющихся вложенными наборами.

В конечном итоге такого разбора всё упирается в элементы-числа. Числа тоже являются базовыми наборами. Это может быть одно число или диапозон.
После компиляции под целевую платформу они превратятся в определённые структуры, подстраиваясь под разрядную сетку нужной архитектуры. На x86 для числового набора _[0:255] (целое беззнаковое со значениями от 0 до 255 включительно) будет байт.

Про второй вопрос: волшебная логика компилятора, это не сложно. Тем более состояние уже описывает какие инструкции выполнить.
Наборы тождественны, если состоят из одинаковых элементов.

Хм. Тождествены ли a, b и b, a?


BTW, а вы понимаете, что ваше "равенство" не транзитивно?


a := {Numerator := 1, Denominator := 0}
b := {Numerator := 2, Denominator := 0}
c := Invalid
a == Invalid //true
b == Invalid //true
a == b //false
a == c //?

Правда, здорово?


Очевидно, что вложенные наборы сравниваются так же, путём вычитания.

Полное структурное сравнение по дереву? Стоимость себе представляете?


Про второй вопрос: волшебная логика компилятора, это не сложно.

state Invalid is {Denominator == 0}
state Valid is {Denominator != 0}

smth := Valid
Вы перепутали сравнение наборов со сравнением состояний.
a == b сравнивает наборы одного пользовательского типа
a == Invalid сравнивает состояние в рамках набора а

По второму случаю я где-то уже писал текущий минус: пока описываются только тождественные условия в состояниях. То есть неравенства сейчас не принимаются. Я над этим работаю.
Вы перепутали сравнение наборов со сравнением состояний.

Я не перепутал, я намеренно подменил. В коде никто никогда не отличит, где состояние, а где набор (особенно если мы захотим передать состояние как параметр). И эта неодинаковость поведения при полной идентичности записи убивает читабельность полностью.


По второму случаю я где-то уже писал текущий минус: пока описываются только тождественные условия в состояниях. То есть неравенства сейчас не принимаются. Я над этим работаю.

… и как же будет работать присвоение в этом случае?

Если видите проблему, то где Ваши предложения?

Можно оставить для состояний только is и добавить какое-либо ключевое слово для перевода набора в нужное состояние. Например, in. Как на Ваш взгляд это повлияет на читаемость?

Можете предложить и свои варианты реализации наборов и операций над ними.

На мой взгляд это направление перспективно для развития языка программирования. Как минимум что-то новое и не топтаться на месте.
Если видите проблему, то где Ваши предложения?

Выкинуть "состояния" вовсе, потому я не вижу профита, которые они бы приносили (в той реализации, которую вы предлагаете). Они прекрасно заменяются предикатами.


добавить какое-либо ключевое слово для перевода набора в нужное состояние. Например, in.

нельзя сделать перевод в (любое) нужное состояние.


Можете предложить и свои варианты реализации наборов и операций над ними.

Я не считаю идею с наборами осмысленной — я не вижу пользы, которую она бы приносила.


На мой взгляд это направление перспективно для развития языка программирования.

Перспектива — это когда видна цель. А пока видно только


что-то новое и не топтаться на месте.

Я не люблю новое ради нового.


Я ведь не зря сразу спросил, как ваш язык решает упомянутые вами же проблемы.

Если в «Сигма» Вы подключите к своему проекту только decimal модуль, то Вы не найдёте у меня True и False.

Только в голову пришло: если у вас нет встроенных булевых операций, то как же делать not, or и and?

Вместо bool теперь будет использоваться bit для работы с двоичной архитектурой. Для набора bit определены булевы операции (подобно операциям присвоения, то есть можно будет код посмотреть). Аналогично для других архитектур.

Какого типа выражение a == b?

Это операция, она может быть переопределена программистом. Если a и b — наборы одного пользовательского типа, то и результат набор пользовательского типа.

… и поскольку это наборы, над ними не определены логические операции, и сделать банальное a == b and c == d я не могу. Восхитительно.


Что еще интереснее, если эта операция возвращает bit, я не могу просто запихнуть ее в if (потому что тот проверяет, пустое ли множество), я должен написать if ((a == b) is True).

Где другие могут видеть дорогу, у Вас полная шляпа.
Всё не так плохо, на крайний случай if может принимать несколько множеств. Выглядеть это может примерно так:
if ( a == b, c == d ) {}

До конца ещё не проработал, но проблемы нет. Приведённый вариант не самый лучший.
Всё не так плохо, на крайний случай if может принимать несколько множеств. Выглядеть это может примерно так:
if ( a == b, c == d ) {}

Это and или or?


До конца ещё не проработал, но проблемы нет

Так как же решается проблема с использование bit в if?


А, вот еще, кстати:


x := {a, b, c}
y := {a, b}
z := {c}

x == y //false
y == z //false
(x == y) == z //true
Продолжаем Вас вербовать.
Это будет аналог and, теперь начинайте кричать «пропал or». Уже жду.

Так как же решается проблема с использование bit в if?

В bit реализовано сравнение с числом, с состоянием и с bit'ом. Лучший существующий аналог это перегрузка оператора в С++.

Про последний пример кода: а чего Вы ожидаете от сравнения наборов, тем более разных типов? Если нужна булева алгебра, сделайте a, b и c наборами типа bit и тогда сравнивайте их между собой.
Вы же в других языках не сравниваете строку и число напрямую?

Темы затронуты хорошие, но я же в самом верху статьи написал, что не преуспел в этом вопросе. Есть вопросы, на которые я пока тоже не знаю ответа, но это не повод говорить стоп для исследователя. Концепция отличная от всего имеющегося есть, базис есть, я поделился идеей с комьюнити. Зря большинство, вместо развития, подводит к мысли выкинь и забудь.
В bit реализовано сравнение с числом, с состоянием и с bit'ом.

Вот только if ничего ни с чем сравнивает — по вашим словам, — он проверяет, что множество пустое.


Про последний пример кода: а чего Вы ожидаете от сравнения наборов, тем более разных типов?

Я ожидаю, что код будет вести себя предсказуемо. А понятие "типа" набора у вас то появляется, то пропадает, и тоже пока что не определено.


Если нужна булева алгебра, сделайте a, b и c наборами типа bit и тогда сравнивайте их между собой.

Я хочу булеву алгебру, встроенную в язык — что позволит стандартным операторам возвращать булевы значения. И это снимет кучу проблем.


Вы же в других языках не сравниваете строку и число напрямую?

Вы не поверите, но сравниваю.


Концепция отличная от всего имеющегося есть

Понимаете ли, концепции недостаточно быть "отличной от имеющегося". Она должна решать какие-то задачи (или хотя бы отвечать на какие-то вопросы). Вы проблемы в посте озвучили, а вот решить их вам не удалось.


Зря большинство, вместо развития, подводит к мысли выкинь и забудь.

Не всякая концепция заслуживает развития только потому, что она отличается от всего имеющегося.


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

а чего Вы ожидаете от сравнения наборов, тем более разных типов?

Я например ожидаю, что сравнение возвращает логический тип, а не тип сравниваемых значений. Потому что иначе это то же самое, что (x-y).


Зря большинство, вместо развития, подводит к мысли выкинь и забудь.

Большинство подводит к мысли, а в чем это поможет, что в этом полезного, чтобы его развивать? Зачем что-то развивать только чтобы догнать существующее?

… на самом деле, проблема с отсутствием встроенных логических типов прекрасно видна и на другом примере. Вот хочу я написать функцию (метод, не важно): IsSystemConfiguredThisWay, чтобы, значит, делать так:


if (IsSystemConfiguredThisWay()) {DoThat()}

Какой тип должна возвращать эта функция? "Любой" набор, и если он пустой, то if пройдет? А если мне надо, чтобы не прошло, вернуть "любой" непустой? А как это выразить в типе функции? В итоге мы получаем все те же самые #DEFINE FALSE {} и падение читаемости/самодокументируемости — строго противоположно тому, что вы хотели.

Можно использовать Лябмда-исчесление для булевой логики! )
Church Booleans

true  = \a b -> a
false = \a b -> b

not p = p false true

p `and` q = p q p
p `or`  q = p p q

ifThenElse p a b = p a b

Можно. Но я лучше лисп возьму тогда.

))) Да, лябда-исчисление то ещё программирование!
Хаскель красивей и лучше. Примерно так определено:
data Bool = False | True

not True  = False
not False = True

True `and` True = True
_    `and` _    = False

False `or` False = False
_     `or` _     = True

class Eq a where
   (==) = not . (/=)
   (/=) = not . (==)

instance Eq Bool where
   True  == True  = True
   False == False = True
   _     == _     = False
вроде как не так часто используется this чтобы экономия двух символов прям решала
Спасибо за хорошую статью!

В ответе на Ваш вопрос, я поддержу критику против моей же идеи. Наборы немного лучше объектов и дают больше свободы. Как писали выше, сейчас есть сложность их применения.

Наборы глубже пронизывают весь язык, чем объекты в Java или C#. В последних языках есть базовые типы (например, byte), посмотреть и контролировать реализацию которых Вы не можете (обычно это не минус, когда речь об одной архитектуре). Все числа преобразуются к этим типам в процессе компиляции. Нередко отдельно рассказывают устройство стандартного массива в языке. В Сигма стремимся убрать эти чёрные ящики, есть числа и наборы. Вместе они описывают всё — от самого приложения до самого базового типа интересующей нас архитектуры.
В теории появляются новые возможности. Например, применяя аспектно-ориентированное программирование прямо в процессе работы приложения возможно убирать и добавлять инструкции в специальных точках соединения (определённых срезом). На практике всех интересует как это будет реализовано на определённой архитектуре, чтобы после оптимизации не выглядело хуже уже существующих решений. Выполнить такие оптимизации возможно, но тогда наборы для людей выглядят тем чёрным ящиком, стыкующим логику и железо. Этого можно избежать, позволив описывать архитектурный код в языке.

Если уж углубляться в теорию множеств, то и числа могут быть выведены из наборов.

Наборы немного лучше объектов и дают больше свободы.

Чем лучше? В чем конкретно выражается "свобода"?


Наборы глубже пронизывают весь язык, чем объекты в Java или C#.

В чем конкретно это выражается?


В Сигма стремимся убрать эти чёрные ящики, есть числа и наборы.

А числа и наборы в Сигме — не черные ящики разве? Как я могу посмотреть реализацию _[0:1] или набора source?


Вместе они описывают всё — от самого приложения до самого базового типа интересующей нас архитектуры.

А если я всегда пишу для одной архитектуры, какой мне профит от необходимости ее определять?


Например, применяя аспектно-ориентированное программирование прямо в процессе работы приложения возможно убирать и добавлять инструкции в специальных точках соединения (определённых срезом).

Эмм, а какие конкретно преимущества наборов позволяют это сделать легче по сравнению с другими АОП-инструментами для других языков?

Вместе они описывают всё — от самого приложения до самого базового типа интересующей нас архитектуры.

А если я всегда пишу для одной архитектуры, какой мне профит от необходимости ее определять?

Хотя интереснее, конечно, другое: а действительно ли можно переиспользовать один и тот же код без модификаций на разных архитектурах? И как конкретно это будет выглядеть (для программиста)?

Пока я не совсем понял, отличается ли «набор» от объекта или нет.
Возможно, «наборы» — это объекты с предикатами?

Единственное ваше изобретение — типы как классы/объекты/наборы.
Правда, какие возможности это даёт — я не совсем понял из ваших примеров
Ага, кроме типов — функции и операторы — тоже объекты/наборы.
Это веселее.
Но, почему-то именно это вы и не описали: "// операторы, методы и их внутренности опущены для наглядности"

Я считал, что эта статья может являться неким введением в тему "для чего создан язык". Что ж, плюсы языка, которые тут отметили, расширение классов до наборов и изменение 1 ключевого слова. Что-то мне подсказывает, что в реальной разработке скорость ввода ключевого слова вообще ни на что не влияет. А вот добавление замечательного нового языка - уже квест для всей команды. Любопытно...

Sign up to leave a comment.

Articles