Здравствуйте, DarkEld3r, Вы писали:
DE>С какой стати? Скажем, ты пишешь либу и (если поведение нельзя легко изменить) накладываешь нежелательные ограничения на клиентский код. Вон alex_public говорит, что в обсуждаемом фреймворке хорошо сделали, что использовали структуры. Складывается впечатление, что они и себя ограничивали и дальнейшее использование. Да, по всей видимости, это хороший компромисс (в рамках языка), но С++ (в этом моменте) оставляет больше свободы.
Кстати в том фреймворке не всё структуры, а только сущности представляющие данные. Т.е. которые собственно и выделяются/удаляются постоянно. Но там есть и классы, используемые для сущностей типа "сам сервер" и т.п. В данном случае это вполне удобное и продуманно выходит. Однако я боюсь, что где-то в другом месте я столкнусь с кодом, в котором разделение классов/структур будет не соответствовать моему вкусу. И тогда данное дефолтное разделение по памяти действительно станет слегка напрягать.
Re[16]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
C>Лень... На shootout были когда-то бенчмарки, но их что-то выпилили.
Ага, т.е. реальных данных нет... А у меня вот есть, причём не откуда-то там, а проведённые своими руками. И в них D заметно уступает только C++, а ту же жабку опережает очень заметно. Причём это с обычным компилятором (dmd). И это всё именно про быстродействия — про объём отжираемой памяти я вообще молчу (специально не замерял, но смотрел на состояние системы в тех же тестах и жабка там дико отжирала в сравнение с D и C++).
C>А чем в Java синхронизация более высокоуровневая, чем в С++-ной?
Имеется в виду наличие готовых инструментов прямо в языке, а не возможность сделать что-то с помощью внешних библиотек (при таком раскладе и в C++ вообще всё есть). Так вот в D есть возможность синхронизации класса — весьма похоже на вариант в Java и явно более высокуровневый, чем обычные блокировки. Хотя лично мне оно не нравится и я как раз предпочитаю использовать два других базовых способа — низкоуровневые блокировки или же модель акторов.
C>Я не вижу в D какой-то модели памяти, отличной от share-everything.
Советую посмотреть на модификатор share (а главное, что означает его отсутствие). А так же на его взаимодействие с модификатором immutable и как это всё влияет (что разрешено, а что нет) например на передачу данных между потоками с помощью сообщений (та самая модель акторов).
C>Ну а асинхронные однопоточные библиотеки — это вообще полное "не шмогла".
Если мы говорим про высоконагруженные серверные решения, то это весьма забавная мысль... )
C>В D для данных общая куча, в любом случае, так как иммутабельность не гарантируется системой типов.
Что-что? ) Как раз в D есть не только const (как в C++), но и immutable, который полностью всё гарантирует. Естественно можно всё сломать, если постараться специально (так же как в C++ каст к void* позволяет убить любые гарантии), но это уже другой вопрос.
C>Кроме того, в D отсутствует нормальный механизм снятия иммутабельности в безопасных условиях. Т.е. в типичном сценарии я могу передать граф объектов из одного потока в другой, но в получателе я смогу только читать их (если не использовать небезопасное приведение типов). В Rust с его понятием владения я могу передавать объекты между потоками, так что получатель может их свободно использовать.
Если очень хочется, то без проблем можно и такое. ) Только тут иммутабельность уже вообще ни причём (данные то реально не такие). А здесь скорее речь о снятие модификатора share. Так вот поддержка подобных вещей естественно есть, так же как и программирование на основе cas.
C>На Rust уже написан Servo, и развивается Rust в сторону как раз замены С++ для сложных систем. Причём развивается активно.
Ну так на C то написано вообще множество мегасложных систем, но это не делает C лучше. По набору архитектурных возможностей я пока не вижу чтобы Rust добрался хотя бы до C++ (а D является шагом ещё дальше). Rust скорее застрял где-то между C и C++, убрав множественные родовые травмы C, но не получив возможности C++.
Хотя это всё естественно только предварительная оценка — реально же Rust ещё не родился, так что посмотрим, посмотрим...
Re[17]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, D. Mon, Вы писали:
DM>Но попытка работать с классами как с value-типами чревата рядом неприятностей, т.к. это плохо совместимо с полиморфизмом. Нужно ли этот момент раскрывать подробнее?
С удовольствием послушал бы подробное объяснение про неприятности.
Единственную проблему вижу в том, что в С++, по умолчанию, всё передаётся по значению. Впрочем, я на какие-то ужасные грабли с этим не натыкался, но теоретически возможна "срезка" по недосмотру. Если бы всё, по умолчанию, передавалось по константной ссылке — было бы проще. Ну и писанины меньше заодно.
Ну и не вижу ничего ужасного в создании объекта класса на стеке и передачи его в функции принимающие интерфейс (базовый класс).
Вообще, мне не очень нравится это разделение на ссылочные типы и типы-значения. Да, это очень много где есть и, вероятно, это просто мои тараканы. Но разве удобно постоянно смотреть, что это за тип?
В С++, на мой взгляд, как раз более логично — если передаёшь по константой ссылке, то обьект останется неизменным. Если по значению — скопируется (и соответственно, тоже не изменится). Для изменений есть ссылки и указатели. В D же недостаточно посмотреть на сигнатуру функции — надо ещё на типы параметров смотреть.
DM>emplace
Да уж, "очень удобно".
Реально не понимаю почему нельзя было "scoped" допилить, чтобы компилятор бил по рукам за передачу ссылки на временный объект куда-то наружу.
DM>В D тоже можно, просто язык подталкивает к менее чреватому ошибками выбору.
Ну про ошибки уже спросил.
Тем не менее, насчёт предотвращения (детских) ошибок — могли бы структуры (они ведь могут быть здоровенными) не передавать по значению.
Кстати, погуглил — пишут, что по константой ссылке нельзя rvalue передавать. Правда что ли? И в каких случаях этот запрет может быть полезен?
Re[17]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
_>Ммм ну я в принципе это и имел в виду. В последнем компиляторе вроде без проблем работает. Хотя я это для теста только проверял, а в реальном коде не приходилось (пока что в используемых библиотеках соотношения class/struct более менее рациональное).
Понятно. Просто привык, что если какую-то фичу обьявляют устаревшей, то предлагают более безопасную/удобную альтернативу (скажем, как произошлo с auto_ptr/shared_ptr в С++), ну и её использование не поощряется.
Re[17]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
C>>Лень... На shootout были когда-то бенчмарки, но их что-то выпилили. _>Ага, т.е. реальных данных нет... А у меня вот есть, причём не откуда-то там, а проведённые своими руками. И в них D заметно уступает только C++, а ту же жабку опережает очень заметно.
Ну не может быть он быстрым с консервативным мусоросборщиком. Просто в принципе не может.
_>Причём это с обычным компилятором (dmd). И это всё именно про быстродействия — про объём отжираемой памяти я вообще молчу (специально не замерял, но смотрел на состояние системы в тех же тестах и жабка там дико отжирала в сравнение с D и C++).
Что за тест?
C>>А чем в Java синхронизация более высокоуровневая, чем в С++-ной? _>Имеется в виду наличие готовых инструментов прямо в языке
В Java это просто стандартизованая рекурсивная блокировка в виде synchronized-блоков, и всё. Более высокоуровневой она не является.
C>>Я не вижу в D какой-то модели памяти, отличной от share-everything. _>Советую посмотреть на модификатор share (а главное, что означает его отсутствие). А так же на его взаимодействие с модификатором immutable и как это всё влияет (что разрешено, а что нет) например на передачу данных между потоками с помощью сообщений (та самая модель акторов).
Посмотрел. Не понял в чём суть — оно же используется для глобальных переменных.
C>>Ну а асинхронные однопоточные библиотеки — это вообще полное "не шмогла". _>Если мы говорим про высоконагруженные серверные решения, то это весьма забавная мысль... )
Ну да.
C>>В D для данных общая куча, в любом случае, так как иммутабельность не гарантируется системой типов. _>Что-что? ) Как раз в D есть не только const (как в C++), но и immutable, который полностью всё гарантирует.
Нет. К примеру, нельзя создавать сложные immutable-структуры — банальное дерево со ссылками в узлах на родителя уже не делается. Я поискал и вообще не нашёл иммутабельных контейнеров, в Сети советы типа "создайте мутабельного и закастите".
_>Если очень хочется, то без проблем можно и такое. ) Только тут иммутабельность уже вообще ни причём (данные то реально не такие). А здесь скорее речь о снятие модификатора share. Так вот поддержка подобных вещей естественно есть, так же как и программирование на основе cas.
Каким образом?
Sapienti sat!
Re[18]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
C>Ну не может быть он быстрым с консервативным мусоросборщиком. Просто в принципе не может.
Я же писал уже на эту тему: не стоит сравнивать масштаб использования GC в языке D и в Java. Если мы возьмём скажем нормальный (уровня Boost'a) C++ код и заменим в нём внутренности (и только их — сами контейнеры естественно лежат везде на стеке) всех stl контейнеров на использование GC, то тогда будет что-то весьма близкое к нормальному коду на D. Надо ли пояснять, насколько подобное далеко от языка Java, в котором GC по сути отвечает вообще за всё?
C>Что за тест?
бывало. Хотя это конечно по другой тематике (не серверы, а обработка потоковых данных). А сейчас мы тестируем как раз данный серверный фреймворк и там результаты вообще потрясающие. Но эти данные я ещё никуда не выкладывал.
C>В Java это просто стандартизованая рекурсивная блокировка в виде synchronized-блоков, и всё. Более высокоуровневой она не является.
Ну в D она ещё чуть более продвинутая (там на класс и т.п.), но в любом случае это всё немного другой уровень, чем ручные блокировки. Хотя естественно сводятся к ним — речь исключительно о наличие фичи в самом языке, а не о возможности реализации вообще.
C>Посмотрел. Не понял в чём суть — оно же используется для глобальных переменных.
1. Главное что означает отсутствие shared — данные принадлежат только одному потоку (точнее имеют свою копию в каждом потоке). И это как бы дефолтное, т.е. такими является большинство данных в обычной программе на D.
2. Если мы хотим передавать данные между потоками, то есть несколько разных путей:
— передавать по значению
— передавать ссылки, но на иммутабельное (такие данные естественно не имеют копий по потокам)
— работать с shared данными
Первые два вариант думаю очевидны (хотя уже они покрывают очень значительный набор потребностей), а вот третий уже сложнее. По сути это как раз обычные данные (как в том же C++, общие для всех потоков), но при этом компилятор знает, что с такими данными опасно производить многие операции и просто не позволяет этого. Спокойно можно делать атомарные и synchronized операции, есть гарантии на последовательность исполнения и т.п. И плюс возможен каст из shared данных в обычные — это по сути объявление, что мы сами отвечаем за всё руками (как в C++). И соответственно тут можно уже сделать всё что угодно, в том числе и передачу владения.
C>Нет. К примеру, нельзя создавать сложные immutable-структуры — банальное дерево со ссылками в узлах на родителя уже не делается. Я поискал и вообще не нашёл иммутабельных контейнеров, в Сети советы типа "создайте мутабельного и закастите".
И модификатор immutable и индификатор shared являются транзитивными.
Re[19]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
_>Я же писал уже на эту тему: не стоит сравнивать масштаб использования GC в языке D и в Java. Если мы возьмём скажем нормальный (уровня Boost'a) C++ код и заменим в нём внутренности (и только их — сами контейнеры естественно лежат везде на стеке) всех stl контейнеров на использование GC, то тогда будет что-то весьма близкое к нормальному коду на D. Надо ли пояснять, насколько подобное далеко от языка Java, в котором GC по сути отвечает вообще за всё?
С чего бы контейнеры будут на стеке?? По факту, единственной оптимизацией в D по сравнению с Java является использование структур. Какие-либо сложные данные через них передавать нельзя — оверхед на копирование всё съедает.
бывало.
Совершенно нерепрезентабельно, тест на скорость обращения к массивам.
C>>В Java это просто стандартизованая рекурсивная блокировка в виде synchronized-блоков, и всё. Более высокоуровневой она не является. _>Ну в D она ещё чуть более продвинутая (там на класс и т.п.), но в любом случае это всё немного другой уровень, чем ручные блокировки. Хотя естественно сводятся к ним — речь исключительно о наличие фичи в самом языке, а не о возможности реализации вообще.
Это всё тот же уровень, вид в профиль. Качественно более высокий уровень — это STM, например. Или сегментированные модели памяти, типа Rust или Erlang.
_>Первые два вариант думаю очевидны (хотя уже они покрывают очень значительный набор потребностей), а вот третий уже сложнее. По сути это как раз обычные данные (как в том же C++, общие для всех потоков), но при этом компилятор знает, что с такими данными опасно производить многие операции и просто не позволяет этого. Спокойно можно делать атомарные и synchronized операции, есть гарантии на последовательность исполнения и т.п. И плюс возможен каст из shared данных в обычные — это по сути объявление, что мы сами отвечаем за всё руками (как в C++). И соответственно тут можно уже сделать всё что угодно, в том числе и передачу владения.
И это всё делает всю эту механику чуть менее, чем бесполезной. В Rust система типов гарантирует сегментированность данных между процессами, что делает возможным приватные мусоросборщики для задач, например. В D это невозможно, так как shared/immutable являются лишь хинтами и легко текут.
Для примера:
import std.stdio;
class Test
{
int a;
};
Test some_global;
void do_something()
{
some_global.a += 1;
}
void main()
{
auto t1 = new Test();
t1.a = 11;
some_global = t1;
do_something();
immutable Test ti = cast(immutable) t1;
writeln(ti.a);
do_something();
writeln(ti.a); //Really immutable, are we?
}
Вывод вполне ожидаемый:
12
13
В Rust такая программа невозможна без мегахаков, помеченных feature-gate'ами. Более того, если в D нет вариантов избежать подобного кода из-за невозможности нормально сразу создать иммутабельный граф объектов, то в Rust всё просто за счёт borrow checker'а — пока я владею уникальной ссылкой на объект, то я его могу безбоязненно мутировать. Соответственно, ненужно и искусственное разделение между структурами и классами.
C>>Нет. К примеру, нельзя создавать сложные immutable-структуры — банальное дерево со ссылками в узлах на родителя уже не делается. Я поискал и вообще не нашёл иммутабельных контейнеров, в Сети советы типа "создайте мутабельного и закастите". _>И модификатор immutable и индификатор shared являются транзитивными.
И как это отвечает на мой вопрос?
Sapienti sat!
Re[5]: Язык D - действительно красота и эффективность в одном флаконе
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, x-code, Вы писали:
XC>>Отмена обязательного return это следсвие возможности рассматривать любой блок кода как выражение.
_>И? Какие преимущества имеем с этого? )
Например ненужность ужасного оператора ?: .
Обычный — if-else может быть выражением.
Пример:
auto a = if(b) 1 else 2;
auto a = 1 + if(b) 1 else 2;
// А вот здесь обычно ошибаются в приоритетах ;)auto a = 1 + b ? 1 : 2;
Ну и многие другие конструкции также.
_>Кстати, в лямбда-функциях естественно можно и без return. Не пойму даже почему в плюсах так не сделали.
Здравствуйте, alex_public, Вы писали:
I>>Все функции в либе асинхронные, имеют два колбека — success, error, а вот код который я привел выглядит как обычный синхронный.
На самом деле — всё ещё интереснее. В этом коде x(), у(), и z() могут быть синхронными и асинхронными — по вкусу.
То есть я могу написать что-то типа requestStockQuotes().updateChart().alert('Done!') I>>Джаваскрипт требует смешное количество кода, что бы убрать спагетти из колбеков. Попробуй для сравнения тоже самое в С++ или D. _>Собственно для реализации подобного метапрограммирование не требуется. Это тривиально реализуется обычными способами.
А можно показать эти "обычные способы" в студию? Ну, то есть чтобы я мог написать аналог на C++, при этом updateChart() — асинхронная, библиотечная; alert() — синхронная, библиотечная, а requestStockQuotes — это асинхронная, самописанная.
Правда при этом будет не максимально эффективно по быстродействию (вызовы не будут инлайниться как минимум).
Какой ещё инлайнинг в асинхронных вызовах?
_>С помощью МП можно подобное записать в статике, так что всё заинлайнится.
Интересно было бы посмотреть. В JS это всё делается путём добавления ссылки на библиотеку.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
C>Ну не может быть он быстрым с консервативным мусоросборщиком. Просто в принципе не может.
Сборщик у него действительно очень медленный, но насилуется он намного меньше. А критичный по скорости код просто сразу пишется без лишних аллокаций и сборок, это не так уж сложно в D.
C>Нет. К примеру, нельзя создавать сложные immutable-структуры — банальное дерево со ссылками в узлах на родителя уже не делается.
Это совершенная неправда, и все дальнейшие твои рассуждения отсюда ложны.
Вот иммутабельное дерево с ссылками на родителя:
immutable class Tree(T) {
T value;
Tree!T left, right, parent;
alias MkT = immutable(Tree!T) delegate(immutable Tree!T);
this(T v, immutable Tree!T prnt, MkT mkLeft, MkT mkRight) {
value = v; parent = prnt;
left = mkLeft(this); right = mkRight(this);
}
this(T v, immutable Tree!T prnt) { this(v, prnt, _ => null, _ => null); }
}
void main(string[] argv)
{
auto t1 = new immutable Tree!int(10, null,
p => new immutable Tree!int(20, p),
p => new immutable Tree!int(30, p));
writeln( t1.left.parent.right.parent.value );
}
(создает дерево с 10 в корне и 20 и 30 в листьях, выводит 10)
Re[20]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
C>В Rust такая программа невозможна без мегахаков, помеченных feature-gate'ами.
Значит все-таки возможна. Разница лишь в простоте использования мегахаков. Просто считай касты в D такими же мегахаками и не используй их. Например, пиши код в режиме @safe, компилятор будет бить по рукам. Не надо путать возможности системы типов и возможности по ее обходу. Начал обходить систему типов — забудь о ее гарантиях.
Re[21]: Язык D - действительно красота и эффективность в одн
Здравствуйте, D. Mon, Вы писали:
DM>Значит все-таки возможна. Разница лишь в простоте использования мегахаков. Просто считай касты в D такими же мегахаками и не используй их. Например, пиши код в режиме @safe, компилятор будет бить по рукам. Не надо путать возможности системы типов и возможности по ее обходу. Начал обходить систему типов — забудь о ее гарантиях.
Но ведь подавляющее большинство кода в режиме @safe не написано. Т.е. в одном случае (Rust) – тебе нужно сильно нопрячься что бы обойти защиту. В другом случае (D) защита по умолчанию отключена. Не находишь что это не совсем равное сравнение?
Re[18]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, DarkEld3r, Вы писали:
DM>>Но попытка работать с классами как с value-типами чревата рядом неприятностей, т.к. это плохо совместимо с полиморфизмом. Нужно ли этот момент раскрывать подробнее? DE>С удовольствием послушал бы подробное объяснение про неприятности. DE>Единственную проблему вижу в том, что в С++, по умолчанию, всё передаётся по значению. Впрочем, я на какие-то ужасные грабли с этим не натыкался, но теоретически возможна "срезка" по недосмотру. Если бы всё, по умолчанию, передавалось по константной ссылке — было бы проще. Ну и писанины меньше заодно.
Слайсинг/срезку действительно часто в этом контексте вспоминают, но есть и еще проще соображения.
Если у нас есть сабтайпинг через наследование и ОО-полиморфизм через виртуальные методы, то допустим у нас есть класс Parent и наследный от него Child с дополнительными полями и оверрайдингом ряда методов. Тогда, раз это подтип, то функция f(Parent a) должна уметь принимать значение типа Child, причем реальный тип аргумента (Parent передается или Child) статически неизвестен. Если мы попробуем передать Child по значению, то либо испортим стек, попытавшись запихать больше байт, чем ожидает функция, либо придется передавать лишь часть объекта (соответствующую полям Parent'a), но поскольку какие-то методы переопределены, они будут думать, что есть все поля Child, а там окажется мусор. В общем, как ни крути, а передавать подобные объекты можно исключительно по ссылке. Они просто не могут быть value-типами. В то же время какие-то value-типы нам все же нужны, ибо нередко нам нужна именно value-семантика, где переданное значение является копией и не зависит от оригинала. Отсюда разделение на reference vs. value типы, отсюда отнесение классов с VMT к первым.
Другой вопрос — почему бы временные объекты не размещать на стеке, продолжая обращаться к ним по ссылкам. В принципе, ничто не мешает. Если компилятор содержит достаточно хороший анализатор, он мог бы делать это автоматически, как это вроде бы делает JVM. Но в D, как я понимаю, такого анализатора нет (и не факт, что язык позволит его сделать), а отдавать на откуп программистам под их ответственность — можно, но лишь продвинутым, поэтому такую возможность сделали менее удобной, лишь для самых настырных.
DE>Тем не менее, насчёт предотвращения (детских) ошибок — могли бы структуры (они ведь могут быть здоровенными) не передавать по значению.
Так можно и не передавать. Пишешь f(ref S x), где S — структура, и все передается по ссылке. Но все-все по ссылке нельзя передавать, ведь value-семантика часто тоже нужна.
DE>Кстати, погуглил — пишут, что по константой ссылке нельзя rvalue передавать. Правда что ли? И в каких случаях этот запрет может быть полезен?
Эту тему давно там педалируют и грозятся исправить, но я как-то не в курсе текущей ситуации.
Re[22]: Язык D - действительно красота и эффективность в одн
Здравствуйте, kaa.python, Вы писали:
KP>Но ведь подавляющее большинство кода в режиме @safe не написано. Т.е. в одном случае (Rust) – тебе нужно сильно нопрячься что бы обойти защиту. В другом случае (D) защита по умолчанию отключена. Не находишь что это не совсем равное сравнение?
Честно говоря, я сам не пробовал форсить @safe, потому не могу сказать, насколько этот вариант юзабельный, и много ли в нем доступно на практике.
Но в целом я согласен, что если определять защищенность не бинарно, а строить градации, то D тяготеет к С/С++ с их рабоче-крестьянской близостью к железу и слабыми гарантиями.
Re[19]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, D. Mon, Вы писали:
DM>Если мы попробуем передать Child по значению, то либо испортим стек, попытавшись запихать больше байт, чем ожидает функция, либо придется передавать лишь часть объекта (соответствующую полям Parent'a), но поскольку какие-то методы переопределены, они будут думать, что есть все поля Child, а там окажется мусор.
Это в каких реалиях? В С++ стек не испортится. Если копирование не запрещено, то будет срезка и да, это почти всегда нежелательно и может приводить к несогласованному состоянию объекта.
DM>почему бы временные объекты не размещать на стеке, продолжая обращаться к ним по ссылкам. В принципе, ничто не мешает. Если компилятор содержит достаточно хороший анализатор, он мог бы делать это автоматически, как это вроде бы делает JVM.
Да можно и без автоматики обойтись. В чём проблема допилить старую возможность (scope)? Ничего сильно анализировать не надо — просто запретить передавать такие объекты за пределы скопа.
DM>Так можно и не передавать. Пишешь f(ref S x), где S — структура, и все передается по ссылке. Но все-все по ссылке нельзя передавать, ведь value-семантика часто тоже нужна.
В курсе. Тут вопрос был слегка в другом (и не только к D относится). Почему нельзя всё-всё передавать по константной ссылке (элементарные типы компилятор мог бы автоматически и по значению передавать, если это эффективнее)? Не было бы срезки, меньше писать (в С++ в куче случаев приходится писать именно "const T &"). Для передачи по ссылке и копирования сделать отдельные ключевые слова.
Re[20]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, DarkEld3r, Вы писали:
DM>>Если мы попробуем передать Child по значению, то либо испортим стек, попытавшись запихать больше байт, чем ожидает функция, либо придется передавать лишь часть объекта (соответствующую полям Parent'a), но поскольку какие-то методы переопределены, они будут думать, что есть все поля Child, а там окажется мусор. DE>Это в каких реалиях? В С++ стек не испортится. Если копирование не запрещено, то будет срезка и да, это почти всегда нежелательно и может приводить к несогласованному состоянию объекта.
Это не в реалиях, а в размышлениях как оно вообще может быть. Либо мы передаем объект целиком, портя стек, либо не целиком (как в С++), но тогда при вызове виртуального метода в нем у него в ряде полей окажется мусор (ибо данные есть только от Parent'a, а методы вызываются от Child'a).
DE>Да можно и без автоматики обойтись. В чём проблема допилить старую возможность (scope)?
Не знаю. Я бы и сам не отказался от такого.
DE>Тут вопрос был слегка в другом (и не только к D относится). Почему нельзя всё-всё передавать по константной ссылке (элементарные типы компилятор мог бы автоматически и по значению передавать, если это эффективнее)? Не было бы срезки, меньше писать (в С++ в куче случаев приходится писать именно "const T &"). Для передачи по ссылке и копирования сделать отдельные ключевые слова.
В некоторых языках примерно так и сделано — данные по умолчанию иммутабельные и передаются по ссылке. В условиях ОО языка передавать все-все по константной ссылке плохо — традиционно объекты мутабельные и передаются, чтобы у них вызывались мутирующие методы. Вот и возникает решение: передавать все объекты классов просто по ссылке, что в D/Java/С# и делается.
Re[21]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, D. Mon, Вы писали:
DM>Это не в реалиях, а в размышлениях как оно вообще может быть.
Ну если так, то я всё-таки за вариант "как в С++", но с другим умолчанием. То есть передаём по константной ссылке. Если надо именно модифицировать или требуется именно копия — указываем явно. Вроде, и никаких потенциальных ошибок не возникнет?
Если вдруг "случайно" внутри функции полезли менять объект — компилятор про это скажет. Дальше или понимаем, что ошиблись и не меняем или меняем сигнатуру функции.
В С++ правда так можно передать ссылку и потом сразу разрушить объект, но для D (с его GC) и Раста это не актуально. И опять же компилятор может отслеживать.
DM>В условиях ОО языка передавать все-все по константной ссылке плохо — традиционно объекты мутабельные и передаются, чтобы у них вызывались мутирующие методы. Вот и возникает решение: передавать все объекты классов просто по ссылке, что в D/Java/С# и делается.
Не согласен.
Во первых, не просто "всё-всё", а "всё-всё по умолчанию".
Во вторых, объекты может и мутабельные, но функции (внешние), зачастую, такими быть не обязаны. Если посмотреть на стандартную библиотеку С++, то немало алгоритмов не модифицирующие. У классов тоже немало функций помеченных как const. Ну в джаве/C# сделали ещё "веселее" — там передать "по константной ссылке" нельзя (в джаве есть final, но это вроде, не то). То есть мы даже не можем "пообещать" не изменять обьект внутри функции.
В третьих, в шарпе и джаве многие обьекты и так иммутабельные (строки, BigInt и т.д.). Мне, кстати, больше по душе подход С++/Д, где мы решаем на уровне объекта, а не на уровне класса, будет ли он константным/иммутабельным или нет.
Re[19]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, D. Mon, Вы писали:
C>>Ну не может быть он быстрым с консервативным мусоросборщиком. Просто в принципе не может. DM>Сборщик у него действительно очень медленный, но насилуется он намного меньше. А критичный по скорости код просто сразу пишется без лишних аллокаций и сборок, это не так уж сложно в D.
Насколько меньше? Я вот смотрю тот же vibe.d — структур там минимум. Почти везде классы.
C>>Нет. К примеру, нельзя создавать сложные immutable-структуры — банальное дерево со ссылками в узлах на родителя уже не делается. DM>Это совершенная неправда, и все дальнейшие твои рассуждения отсюда ложны. DM>Вот иммутабельное дерево с ссылками на родителя:
Вах! Я и не думал, что всё так плохо.
Оказывается, можно и с помощью полностью "безопасного" кода на D всё сломать.
import std.stdio;
immutable class Test
{
int a;
alias setter_tp = void function(immutable Test);
this(setter_tp setter)
{
setter(this);
a = 1;
}
};
void doSomeLazyInit(immutable Test t)
{
writeln(t.a); //Тут мы можем объект послать в другой поток, для примера
}
void main()
{
auto a = new immutable Test(&doSomeLazyInit);
writeln(a.a);
}
Если постараться, то я и memory corruption так легко устрою с помощью immutable.
Sapienti sat!
Re[21]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, D. Mon, Вы писали:
C>>В Rust такая программа невозможна без мегахаков, помеченных feature-gate'ами. DM>Значит все-таки возможна. Разница лишь в простоте использования мегахаков. Просто считай касты в D такими же мегахаками и не используй их.
В D невозможно писать нетривиальный код без хаков — явных или неявных, типа возможности мутации объектов в конструкторе. В Rust же хаки в большинстве программ просто не нужны.
Sapienti sat!
Re[21]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
_>Я с удовольствием и МП пообсуждаю (люблю эту тему). А здесь я просто уточнил, МП из каких языков имеет смысл сравнивать при обсуждение возможностей D. Потому как если сравнивать скажем с Питоном, то это будет просто смешно, т.к. речь о вообще ином мире. Хотя формально это всё вроде как МП.
Сравнивать можно любой язык с любым — эффект, затраты, возможности и тд.