Хорошее замечание. Да, извиняюсь, я ошибся и, видимо, сделал слишком сильное утверждение. Сделать хранимое свойство вычисляемым с помощью одного только изменения определения в общем случае не получится.
Но, возвращаясь к нашей теме, это не отменяет того, что хранимое свойство может стать вычисляемым (да, это может быть не однострочным изменением в общем случае), вычисляемое — хранимым, и свойство может переехать в другую таблицу. Классы при этом никак не изменятся.
Без изменения кода, но с полным сохранением поведения? Что-то верится с трудом, извините уж.
Не без изменения кода, а с минимальным измнением в коде, меняется только определение свойства. Ну и верить нам, конечно, не нужно. Можно все попробовать на практике.
Я тогда не совсем понял. Было утверждение, что свойство где-то хранится и класс будет соответсвовать этому хранилищу. А я говорю о том, что у нас свойство может храниться, а потом стать вычисляемым или наоборот. Или может храниться в одной таблице, а потом переехать в другую. Почему это не повлияет на классы при таком определении сущностей?
И еще, я не хочу ввязываться в священные войны или долгие споры, я пытаюсь объяснить в меру возможностей, почему у нас сделано так, а не иначе.
Вы сейчас пробуете предложить вариант, где физическая модель прибита гвоздями к логической? Мы сейчас с нашим подходом можем менять физическую модель без изменения классов: перекладывать свойства в другие таблицы, можем материализовывать свойства в любой момент и возвращать это обратно. Если взять вашу схему, то при каждом таком изменении нужно (ведь таблица, где хранится свойство, изменится) менять классы: создавать их, удалять, объединять, разбивать, а это у нас в свою очередь повлияет на огромное количество вещей. То есть при материализации свойства, а это частая операция, нам придется существенно менять код, да и кроме этого будет куча других проблем, начиная с миграций и логики представлений. Cпасибо, конечно, но нам это не подойдет.
Я сказал «примерно так». В другой ситуации, когда, например, Sku и Stock — это некие производные классы, физическая модель может быть не такой. И эту физическую модель мы можем менять в продакшене.
Ну и да, к синтаксису задания свойств одного класса это не имеет никакого отношения.
Да, можно сделать отдельный синтаксис для частного случая, можно даже и не для частного сделать, как я предлагал в другом комментарии. Тут вопрос, насколько это будет оправдано. Мое личное мнение, которое может не совпадать с политикой компании :), что частный случай точно не нужно добавлять в язык, а перед добавлением общего случая нужно оценить, насколько этот дополнительный синтаксис вообще вписывается в логику, грамматику языка, насколько нужно будет изменять другие конструкции, не будет ли стилистического винегрета (его и так у нас хватает по разным причинам), что нужно сделать, чтобы поддержать это в плагине к intellij.
Где у вас хранятся значения для таких свойств?
В таблице с несколькими ключевыми полями, это есть в этой статье, которую мы обсуждаем.
Как ни странно, это совершенно не нужно для того, чтобы реализовать написанное выше предложение
Да, тут согласен. Но что я вообще хотел бы заметить: можно обсуждать какую-то языковую конструкцию в отрыве от остальной части языка и придумать красивое и элегантное решение, которое абсолютно не будет вписываться в уже имеющийся синтаксис. Редко бывает, что есть изменение в языке, не несущее минусов (хотя бы просто минус от добавления новой конструкции, которую нужно учить). Но это так, лирическое отступление.
Ну, вы же по какому-то «событию» создаете запись в БД, которая содержит количество этого товара на этом складе? А она и есть этот «объект». И с удалением то же самое.
Да, если свойство DATA или материализованное, то создаем, для остальных нет.
Ну и я, наверное, даже не столько про физическую сторону вопроса говорил, сколько про логическую. Создается ведь куча дополнительных логических связностей между такими классами, разве нет? (я сейчас не про вариант с кортежами).
Да в таком синтаксисе нужно будет делать как-то так. Только вот кажется, что будет слишком много EXTEND CLASS инструкций в модулях, использующих классы из других модулей.
Но опять же мы все-таки хотели иметь возможность не создавать классы для свойств, зависящих от нескольких равноправных сущностей. Можно, конечно, для этой цели использовать какой-нибудь вот такой синтаксис: (Item i, Store s) {
property1;
...
propertyN;
}
Не уверен, правда, насколько это будет выглядеть чище, когда дело дойдет до расширений. Нужно смотреть.
Я не предлагаю делать их центральной сущностью. Я говорю о том, что оба варианта абсолютно эквивалентны, но во втором меньше информационного шума и копипасты.
А мне кажется предложение для всех комбинаций классов создавать новый класс — это как раз делать класс центральной сущностью, как в условной Java.
Оно не принадлежит ни товару, ни складу, оно принадлежит третьему классу.
Ну а мы пошли по другому пути: мы можем не создавать новый класс, когда нам нужно свойство от нескольких равноправных сущностей. Это позволяет не создавать объекты (товар, склад) (объекты же будут у этого класса?), потому что с этими объектами есть сложности, например, их когда-то нужно создавать и удалять.
Например, пользователь создал новый объект класса товар, теперь хочет переместить его на склад, в этом случае должен быть создан объект (товар, склад), то есть по какому-то событию нам нужно добавлять этот объект. Теперь пользователь удалил товар, нам теперь надо (надо ведь?) удалить объект (товар, склад), то есть опять же должно быть какое-то событие, по которому будет происходить удаление этого объекта. А если у нас класс товар участвует в большом количестве таких объединяющих классов?
И я хотел бы заметить, что мы обсуждаем lsfusion, отвечаем на вопросы, почему у нас синтаксис именно такой, а не иной. Когда мы используем слово «свойство», мы имеем ввиду термин из lsfusion. Если мы будем говорить на разных языках, то друг друга так и не услышим.
Тем более, это наоборот подтверждает то, о чем я говорю. Машина не может прочитать формализованный и структурированный язык программирования, приходится подсказки давать. Не только для человека выразительность недостаточная, но и даже для машины.
Эти комментарии указывают на блок кода, то есть с какой по какую строчку исходного файла надо вставить в confluence. Это просто нарезка большого файла на кусочки, никакого отношения к выразительности языка это не имеет.
Оно не принадлежит ни товару, ни складу, оно принадлежит третьему классу.
В классическом ООП с инкапсуляцией оно будет принадлежать третьему классу, да. А у нас оно «принадлежит» паре классов (товар, склад), в этом разница. В результате этого мы можем получить при желании множественную диспетчеризацию (это расширение функциональности виртуальных методов). В языках же с классическим ООП для этого конкретного случая придется использовать, например, Visitor, который может реализовать двойную диспетчеризацию (double dispatch). Для случая с тремя классами будет вообще все сложно.
У нас есть более-менее сложившаяся терминология, которая используется в документации. Но здесь в комментариях я, например, иногда отхожу от этой терминологии, потому что говорить с людьми на незнакомом им языке не совсем разумно. В моем комментарии выше из терминов lsfusion используются: свойство, действие, класс, абстрактное свойство/действие, модуль. Вроде бы все, остальное — просто слова.
В lsfusion классы не являются центральной сущностью, вокруг которой строится остальная логика, в lsfusion главными и первичными яляются свойства и действия, а классы выступают в роли ограничений, фильтров. Да, с них удобно начинать объяснение, но это следствие того, что так большинству людей привычней.
Такой синтаксис также является следствием отсутсвия у нас инкапсуляции в том значении этого термина, где речь идет об объединении данных и методов работы с ними. То есть у нас свойства и действия не привязаны к какому-то одному главному классу. Если искать близкий аналог, то наши свойства — это что-то вроде мультиметодов, что дает возможность, например, subtype полиморфизма по нескольким параметрам. Реализуется это в lsfusion с помощью абстрактных (ABSTRACT) свойств и действий.
Также это дает нам возможность «расширять классы» новыми свойствами и действиями в разных модулях, обеспечивая модульность и позволяя нам компоновать необходимую функциональность с помощью выбора нужного множества модулей. Да, такого можно было добиться и открытыми классами c инкапсуляцией, как, например, в ruby, но наш подход — это следствие того, что свойства первичны, а классы вторичны. То есть свойство, зависящее, например, от товара и склада при нашем подходе не «принадлежит» ни товару, ни складу.
Даже в вашем примере вы обозначаете комментариями начало и конец структуры, это говорит о том, что выразительность языка недостаточная.
Эти комментарии — это разметка для скрипта, который формирует html'ки для confluence, который мы используем для документации. Это учебный пример из документации, поэтому он так размечен, выразительность языка тут не при чем.
Я понимаю, что это всего лишь перевод статьи с geeksforgeeks (образовательные статьи с geeksforgeeks?) по очень избитой теме, но перевести ведь можно и получше, есть ведь какая-то общепринятая терминология в русском языке.
1. «Законченное двоичное дерево».
Возможно, этот термин где-нибудь и применяется, но обычно это либо называют «полным двоичным деревом», либо вообще никак не называют, описывая правила построения
2. «Пирамидальная сортировка — это вполне годный алгоритм. Его типичная реализация не стабильна, но может быть таковой сделана».
Не стабильна, близка к распаду. Вроде бы обычно в русском языке термин «stable sort» называют «устойчивой сортировкой».
3. Описание алгоритма.
«Наконец, преобразуйте полученное дерево в max-heap с новым корнем.».
В оригинале ведь все куда более конкретно: «Finally, heapify the root of tree.» и затем идет описание того, что же такое «heapify». В переводе термин «heapify» потерян, из-за этого логика становится куда более размытой.
Также третий пункт описания алгоритма «Повторяйте вышеуказанные шаги, пока размер кучи больше 1.» в оригинале написан неудачно (не очень понятно. нужно повторять шаги 1 и 2 или только 2), и тут также оставлен без изменений (причем русскоязычный вариант субъективно еще менее понятный).
В результате по описанию этого простого алгоритма, на мой взгляд, вообще мало что понятно без чтения кода или дополнительного поиска информации (что возвращает нас к теме качества статей на geeksforgeeks).
Я все-таки еще раз влезу. Уже целая куча сообщений в этой ветке из-за непонимания друг друга. Дело в том, что когда NitroJunkie написал «множество всех значений функции» имел он ввиду все-таки (если я не прав, то скажи) все то же множество всех наборов аргументов, для которых функция определена (ее значение от этих аргументов не равно NULL). Область определения функции, если угодно.
Интересует вопрос — а как вы работаете с миграциями? Накидали кода, развернули сервак, бабах — перименовали в коде кучу свойств, как оно потом всё это обрабатывает?
Если вкратце, то у нас есть миграционные скрипты, в которые при переименовании, например, свойств/действий из IDE будут автоматически вставляться строки миграции. Вообще, вопрос правильный, и в направлении миграции у нас еще есть что улучшать, потому что, если вы вдруг захотите переименовать все классы и/или переразбить их на другие пространства имен, то сделать это будет не так просто.
Но, возвращаясь к нашей теме, это не отменяет того, что хранимое свойство может стать вычисляемым (да, это может быть не однострочным изменением в общем случае), вычисляемое — хранимым, и свойство может переехать в другую таблицу. Классы при этом никак не изменятся.
И еще, я не хочу ввязываться в священные войны или долгие споры, я пытаюсь объяснить в меру возможностей, почему у нас сделано так, а не иначе.
Да, можно сделать отдельный синтаксис для частного случая, можно даже и не для частного сделать, как я предлагал в другом комментарии. Тут вопрос, насколько это будет оправдано. Мое личное мнение, которое может не совпадать с политикой компании :), что частный случай точно не нужно добавлять в язык, а перед добавлением общего случая нужно оценить, насколько этот дополнительный синтаксис вообще вписывается в логику, грамматику языка, насколько нужно будет изменять другие конструкции, не будет ли стилистического винегрета (его и так у нас хватает по разным причинам), что нужно сделать, чтобы поддержать это в плагине к intellij.
В таблице с несколькими ключевыми полями, это есть в этой статье, которую мы обсуждаем.
Да, если свойство DATA или материализованное, то создаем, для остальных нет.
Ну и я, наверное, даже не столько про физическую сторону вопроса говорил, сколько про логическую. Создается ведь куча дополнительных логических связностей между такими классами, разве нет? (я сейчас не про вариант с кортежами).
Но опять же мы все-таки хотели иметь возможность не создавать классы для свойств, зависящих от нескольких равноправных сущностей. Можно, конечно, для этой цели использовать какой-нибудь вот такой синтаксис:
(Item i, Store s) {
property1;
...
propertyN;
}
Не уверен, правда, насколько это будет выглядеть чище, когда дело дойдет до расширений. Нужно смотреть.
А мне кажется предложение для всех комбинаций классов создавать новый класс — это как раз делать класс центральной сущностью, как в условной Java.
Ну а мы пошли по другому пути: мы можем не создавать новый класс, когда нам нужно свойство от нескольких равноправных сущностей. Это позволяет не создавать объекты (товар, склад) (объекты же будут у этого класса?), потому что с этими объектами есть сложности, например, их когда-то нужно создавать и удалять.
Например, пользователь создал новый объект класса товар, теперь хочет переместить его на склад, в этом случае должен быть создан объект (товар, склад), то есть по какому-то событию нам нужно добавлять этот объект. Теперь пользователь удалил товар, нам теперь надо (надо ведь?) удалить объект (товар, склад), то есть опять же должно быть какое-то событие, по которому будет происходить удаление этого объекта. А если у нас класс товар участвует в большом количестве таких объединяющих классов?
И я хотел бы заметить, что мы обсуждаем lsfusion, отвечаем на вопросы, почему у нас синтаксис именно такой, а не иной. Когда мы используем слово «свойство», мы имеем ввиду термин из lsfusion. Если мы будем говорить на разных языках, то друг друга так и не услышим.
Эти комментарии указывают на блок кода, то есть с какой по какую строчку исходного файла надо вставить в confluence. Это просто нарезка большого файла на кусочки, никакого отношения к выразительности языка это не имеет.
В классическом ООП с инкапсуляцией оно будет принадлежать третьему классу, да. А у нас оно «принадлежит» паре классов (товар, склад), в этом разница. В результате этого мы можем получить при желании множественную диспетчеризацию (это расширение функциональности виртуальных методов). В языках же с классическим ООП для этого конкретного случая придется использовать, например, Visitor, который может реализовать двойную диспетчеризацию (double dispatch). Для случая с тремя классами будет вообще все сложно.
В lsfusion классы не являются центральной сущностью, вокруг которой строится остальная логика, в lsfusion главными и первичными яляются свойства и действия, а классы выступают в роли ограничений, фильтров. Да, с них удобно начинать объяснение, но это следствие того, что так большинству людей привычней.
Такой синтаксис также является следствием отсутсвия у нас инкапсуляции в том значении этого термина, где речь идет об объединении данных и методов работы с ними. То есть у нас свойства и действия не привязаны к какому-то одному главному классу. Если искать близкий аналог, то наши свойства — это что-то вроде мультиметодов, что дает возможность, например, subtype полиморфизма по нескольким параметрам. Реализуется это в lsfusion с помощью абстрактных (ABSTRACT) свойств и действий.
Также это дает нам возможность «расширять классы» новыми свойствами и действиями в разных модулях, обеспечивая модульность и позволяя нам компоновать необходимую функциональность с помощью выбора нужного множества модулей. Да, такого можно было добиться и открытыми классами c инкапсуляцией, как, например, в ruby, но наш подход — это следствие того, что свойства первичны, а классы вторичны. То есть свойство, зависящее, например, от товара и склада при нашем подходе не «принадлежит» ни товару, ни складу.
Эти комментарии — это разметка для скрипта, который формирует html'ки для confluence, который мы используем для документации. Это учебный пример из документации, поэтому он так размечен, выразительность языка тут не при чем.
1. «Законченное двоичное дерево».
Возможно, этот термин где-нибудь и применяется, но обычно это либо называют «полным двоичным деревом», либо вообще никак не называют, описывая правила построения
2. «Пирамидальная сортировка — это вполне годный алгоритм. Его типичная реализация не стабильна, но может быть таковой сделана».
Не стабильна, близка к распаду. Вроде бы обычно в русском языке термин «stable sort» называют «устойчивой сортировкой».
3. Описание алгоритма.
«Наконец, преобразуйте полученное дерево в max-heap с новым корнем.».
В оригинале ведь все куда более конкретно: «Finally, heapify the root of tree.» и затем идет описание того, что же такое «heapify». В переводе термин «heapify» потерян, из-за этого логика становится куда более размытой.
Также третий пункт описания алгоритма «Повторяйте вышеуказанные шаги, пока размер кучи больше 1.» в оригинале написан неудачно (не очень понятно. нужно повторять шаги 1 и 2 или только 2), и тут также оставлен без изменений (причем русскоязычный вариант субъективно еще менее понятный).
В результате по описанию этого простого алгоритма, на мой взгляд, вообще мало что понятно без чтения кода или дополнительного поиска информации (что возвращает нас к теме качества статей на geeksforgeeks).
CONSTRAINT password(User u) == password(BlackListItem item) MESSAGE 'пользователь не может иметь пароль, входящий в блеклист'
Если вкратце, то у нас есть миграционные скрипты, в которые при переименовании, например, свойств/действий из IDE будут автоматически вставляться строки миграции. Вообще, вопрос правильный, и в направлении миграции у нас еще есть что улучшать, потому что, если вы вдруг захотите переименовать все классы и/или переразбить их на другие пространства имен, то сделать это будет не так просто.
Более подробно можно прочитать здесь