Снова D: Зверёк читает мануал
От: Зверёк Харьковский  
Дата: 02.05.05 19:15
Оценка: 17 (4)
Предыстория вопроса
D — интересный язык, который мы тут обсуждаем в последнее время
Автор: c-smile
Дата: 01.05.05
. Я начал изучать его недавно, и он мне нра В "Дизайне и Эволюции С++" был такой пассажик: Бьерн сомневается, в правильном ли направлении он движется, и один из создателей языка С успокаивает его фразой "С++ — это то, чем бы мы сделали С, если бы могли". Так, вот, при ознакомлении с D у меня временами (далеко не всегда!) возникает впечатление, что D — это то, чем мог бы быть С++.

Так вот — сейчас сижу читаю мануал этого забавного языка. И возникло у меня желание делиться с окружающими интересными фактами. А раз возникло — то этим я в этой ветке и займусь. Цель этого мне видится не в ознакомлении всего РСДНа с новым языком — а в обсуждении новых или не очень концепций D и их реализации. В конце концов, если это никому не интересно — бомбочек навешаете и всех делов
Поехали!



Перегрузка операторов
Хорошая новость: она есть. Но выглядит несколько... вычурно, что ли?
В С++ мы имеем "естественный синтаксис:
class A
{
...
    int operator+(int);        //оператор сложения A+int
...
}

В принципе, такой синтаксис в некоторой степени самоописателен.

В D та же задача решается следующим способом:
class A
{
...
    int opAdd(int);        //оператор сложения A+int - функция со "специальным" именем opAdd
...
}

Результат, как бы, тот же. Но выглядит это слегка менее очевидно.
Зачем это сделано?
Во-первых, один из design goals языка D — упрощение (по сравнению с С++) лексического/синтаксического анализатора (поэтому D вообще больше склонен к словам, чем к "значками").
Во-вторых, при этом достигается довольно интересный эффект:
A a;
double d = 1/a;     //как написать кастомный оператор для этого случая?


В С++ выходом из этой ситуации стали операторы — свободные функции:
class A
{
...
};

double operator/(int, A&);

А вот в D — "несимметричные операторные функции" ((с) термина мой):
class A
{
    double opDiv_r(int, A&);    //opDiv + _r (right)
};


Мне, откровенно говоря, такой подход нравится существенно меньше — уж очень это напоминает некоторые "неявные соглашения", которые способствуют упрощению компилятора, но не самодокументированию кода. Впрочем, думаю, привыкнуть можно

А вот — очень интересная фича операторов D: они в явном виде поддерживают "зависимые операторы":
//C++
A a, b;
if(a == b)    ...            //вызов A.operator==
if(a != b)    ...            //вызов A.operator!=

//D
A a, b;
if(a == b)    ...            //вызов A.opEquals
if(a != b)    ...            //вызов !A.opEquals

то есть оператора != не существует по определению.

И даже более того: все четыре сравнения (>, <, >=, <=) выполняются одним оператором opCmp:

//C++
A a, b;
if(a > b)    ...            //вызов A.operator>
if(a < b)    ...            //вызов A.operator<
//...и т.д.

//D
A a, b;
if(a <  b)    ...            //вызов A.opCmp(b) <  0
if(a >  b)    ...            //вызов A.opCmp(b) >  0
if(a <= b)    ...            //вызов A.opCmp(b) <= 0
if(a >= b)    ...            //вызов A.opCmp(b) >= 0

...и вот эта фичка (несмотря на не совсем очевидное действие сравнения результата с нулем) мне кажется весьма достойной. Как и любые другие, позволяющие записывать всеобщие неявные соглашения (например: оператор != эквивалентен отрицанию оператора ==) в явном виде. Выигрыш имеем двойной: а) уверенность, что в чужом коде определены и корректно работают все операторы сравнение + б) отстутсвие необходимости повторять "руками" дурную работу.
Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.

К слову, эта идея (избавления от "ненужных операторов") не распространена на операторы вида op= (+=, -= и т.д.). Почему? То есть, конечно, логику в этом, видимо, можно найти... Но лень.

Уф... умаялся. Все пока.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re: Снова D: Зверёк читает мануал
От: c-smile Канада http://terrainformatica.com
Дата: 02.05.05 19:33
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>Мне, откровенно говоря, такой подход нравится существенно меньше — уж очень это напоминает некоторые "неявные соглашения", которые способствуют упрощению компилятора, но не самодокументированию кода. Впрочем, думаю, привыкнуть можно


В общем и целом согласен.
Пара "но" разве что.
1) Не так часто переопределяются операторы.
2) Если нужно "унутре" позвать функцию оператор то явный вызов opShift() выглядит наверное лучше.

"Батенька, да вы эстет как я погляжу..."
Зверёк читает мануал: properties
От: Зверёк Харьковский  
Дата: 03.05.05 01:45
Оценка: :)
Свойства aka properties

Решение этого вопроса довольно изящно: без введения дополнительного ключевого слова и особого синтаксиса:
//Это - С++:
class A
{
    int val();                //getter
    int val(int _newval);    //setter (собака такая - сеттер)
}

A a;
int i = a.val();
a.val(i);

//==============================
//А вот это - уже D:
class A
{
    int val();                //getter
    int val(int _newval);    //setter
}

A a;
int i = a.val;    //вызывается A.val();
a.val = i;        //вызывается A.val(int);


Лихо? Это еще не все. Данные имеют свойства:
int[] arr;        //что написано, то и есть - это динамический массив int'ов

for(int i = 0; i < arr.length; ++i)        //использование свойства массива .length

a.length = 42;                            //еще одно использование свойства


Зашибись? Но и это еще не все. Типы тоже имеют свойства:
int maxint  = int.max;  //максимальное значение int'а
int sizeint = int.size;    //эта фенечка вместо С-шного sizeof(int)

float.nan                //NaN
float.infinity            //бесканечнасть

(2).max                    //эквивалентно int.max
2.max                    //ошибка - у числа 2 нету свойствов


Еще есть такое забавное свойство .init — значение, которым инициализируется переменная:
int val = int.init;        //получим 0
int a;
val = a.init;            //получим 0 - потому что a было проинициализировано нулем

int b = 8;
val = b.init;            //получим 8

typedef int mycoolint = 2;
val = mycoolint.init;    //получим 2
mycoolint c;
val = c.init;            //получим 2


Вставляет? Мне тоже
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re: Зверёк читает мануал: properties
От: c-smile Канада http://terrainformatica.com
Дата: 03.05.05 03:08
Оценка: +2
Здравствуйте, Зверёк Харьковский, Вы писали:


Поправка

int sizeint = int.sizeof; //эта фенечка вместо С-шного sizeof(int)

Дополнение:

В D typedef вводит новый тип, а не алиас как в C++.

т.е.

typedef uint Color; 
Color c; 
c += 28; // ошибка компиляции.


alias int myint; // это то что в C++ typedef.
Re: Снова D: Зверёк читает мануал
От: Mamut Швеция http://dmitriid.com
Дата: 03.05.05 06:35
Оценка: +1 -1 :))) :)))
[offtop]

На смену волне Обероновой пришла волна D

[/offtop]
... << RSDN@Home 1.1.4 beta 6 rev. 433>>


dmitriid.comGitHubLinkedIn
Re: Снова D: Зверёк читает мануал
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.05.05 07:29
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>
ЗХ>//C++
ЗХ>A a, b;
ЗХ>if(a > b)    ...            //вызов A.operator>
ЗХ>if(a < b)    ...            //вызов A.operator<
ЗХ>//...и т.д.

ЗХ>//D
ЗХ>A a, b;
ЗХ>if(a <  b)    ...            //вызов A.opCmp(b) <  0
ЗХ>if(a >  b)    ...            //вызов A.opCmp(b) >  0
ЗХ>if(a <= b)    ...            //вызов A.opCmp(b) <= 0
ЗХ>if(a >= b)    ...            //вызов A.opCmp(b) >= 0
ЗХ>

ЗХ>...и вот эта фичка (несмотря на не совсем очевидное действие сравнения результата с нулем) мне кажется весьма достойной. Как и любые другие, позволяющие записывать всеобщие неявные соглашения (например: оператор != эквивалентен отрицанию оператора ==) в явном виде. Выигрыш имеем двойной: а) уверенность, что в чужом коде определены и корректно работают все операторы сравнение + б) отстутсвие необходимости повторять "руками" дурную работу.
ЗХ>Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.

Вот именно. В C++ мне время от времени приходится использовать в качестве ключей в map объекты, содержащие несколько полей:
struct    Compound_Key
{
    Some_Key_Type    a_;
    Another_Key_Type    b_;
};

Так вот в C++ мне достаточно определить только оператор "строго меньше", который, впрочем, сильно читабельным тоже не выглядит:
bool operator( const Compound_Key & o ) const
    {
        return ( a_ < o.a_ || ( a_ == o.a_ && b_ < o.b_ ) );
    }


Но в C++ я делаю только то, что мне нужно. А вот в D, как я понял, потребуется сделать Compound_Key.opCmp, который должен будет отслеживать не только "строго меньше", но и равенство, и "строго больше".
... << RSDN@Home 1.1.4 beta 6a rev. 436>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Снова D: Зверёк читает мануал
От: WolfHound  
Дата: 03.05.05 07:42
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>
ЗХ>//C++
ЗХ>A a, b;
ЗХ>if(a > b)    ...            //вызов A.operator>
ЗХ>if(a < b)    ...            //вызов A.operator<
ЗХ>//...и т.д.

ЗХ>//D
ЗХ>A a, b;
ЗХ>if(a <  b)    ...            //вызов A.opCmp(b) <  0
ЗХ>if(a >  b)    ...            //вызов A.opCmp(b) >  0
ЗХ>if(a <= b)    ...            //вызов A.opCmp(b) <= 0
ЗХ>if(a >= b)    ...            //вызов A.opCmp(b) >= 0
ЗХ>

ЗХ>...и вот эта фичка (несмотря на не совсем очевидное действие сравнения результата с нулем)
На С++ это делается так:
bool operator < (Some const& l, Some const& r)
{
...
}
bool operator > (Some const& l, Some const& r)
{
    return r < l;
}
bool operator <= (Some const& l, Some const& r)
{
    return !(r < l);
}
bool operator >= (Some const& l, Some const& r)
{
    return !(l < r);
}
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Снова D: Зверёк читает мануал
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 03.05.05 08:05
Оценка: :))) :))) :)))
Здравствуйте, Mamut, Вы писали:

M>[offtop]


M>На смену волне Обероновой пришла волна D


M>[/offtop]


Обероны компактнее.

Если сложить полные описания всех более-менее известных оберонов, то, думается, описание языка D все равно будет больше их в несколько раз
Re[2]: Снова D: Зверёк читает мануал
От: Зверёк Харьковский  
Дата: 03.05.05 09:32
Оценка:
Здравствуйте, WolfHound, Вы писали:

ЗХ>>
ЗХ>>//D
ЗХ>>A a, b;
ЗХ>>if(a <  b)    ...            //вызов A.opCmp(b) <  0
ЗХ>>if(a >  b)    ...            //вызов A.opCmp(b) >  0
ЗХ>>if(a <= b)    ...            //вызов A.opCmp(b) <= 0
ЗХ>>if(a >= b)    ...            //вызов A.opCmp(b) >= 0
ЗХ>>

ЗХ>>...и вот эта фичка (несмотря на не совсем очевидное действие сравнения результата с нулем)
WH>На С++ это делается так:
WH>
WH>bool operator < (Some const& l, Some const& r)
WH>{
WH>...
WH>}
WH>bool operator > (Some const& l, Some const& r)
WH>{
WH>    return r < l;
WH>}
WH>bool operator <= (Some const& l, Some const& r)
WH>{
WH>    return !(r < l);
WH>}
WH>bool operator >= (Some const& l, Some const& r)
WH>{
WH>    return !(l < r);
WH>}
WH>


Никто ж не спорит! Я что подчеркнул — что в D эта "традиция" присутствует в языке в явном виде, а не отдана воле разработчика.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[3]: Снова D: Зверёк читает мануал
От: WolfHound  
Дата: 03.05.05 10:17
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Обероны компактнее.


СГ>Если сложить полные описания всех более-менее известных оберонов, то, думается, описание языка D все равно будет больше их в несколько раз


На размер описания языка начхать всем кроме разработчиков компилятора.
А для пользователей языка важна компактность записи тех или иных конструкций в языке. А вот с компактностью записи у оберонов проблемы.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Снова D: Зверёк читает мануал
От: WolfHound  
Дата: 03.05.05 10:19
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>Никто ж не спорит! Я что подчеркнул — что в D эта "традиция" присутствует в языке в явном виде, а не отдана воле разработчика.

Ну я еще намекнул на то что ребята както странно подходят к реализации одних операций сравнения через другие.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Снова D: Зверёк читает мануал
От: FR  
Дата: 03.05.05 10:26
Оценка:
Здравствуйте, Зверёк Харьковский,

У меня прямо дежавю какое то, все как в питоне
Re[3]: Снова D: Зверёк читает мануал
От: Privalov  
Дата: 03.05.05 10:36
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Обероны компактнее.


СГ>Если сложить полные описания всех более-менее известных оберонов, то, думается, описание языка D все равно будет больше их в несколько раз


Этот вопрос, IMHO, несколько месяцев назад разобрали достаточно основательно. Считаю, что нет смысла к нему возвращаться. К тому же здесь это оффтоп.
Re[4]: offtop
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 03.05.05 11:18
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>На размер описания языка начхать всем кроме разработчиков компилятора.

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

Во-первых, не кипятитесь Вы так. Я же пошутил !!!

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

Вот что пишут про одну из новейших оберонистых операционок:

For a native multiprocessor operating system, Aos is small, with a kernel of 7,210 lines of source or about 50KB of object code. For comparison, the 4.4BSD kernel (cf. 8.1.2) consists of 58,289 lines of C code (excluding file systems, network protocols and device drivers, which add another 143,962 lines) [65]. Version 2.4 of the Linux kernel consists of approximately 420,000 lines of C code (excluding drivers, file systems and architecture-specific code, which bring the total to 2.4 million lines) [128], and has a minimum size of around 500KB on Intel processors. Microsoft boasts that Windows 2000 “consists of over 29 million lines of code”, but does not say what is included in this figure, so it is not possible to compare specifics.

Subsystem        Lines

Kernel            7210
Service support   2532
File system       4624
User interface    2204
Network           6200
Oberon for Aos    8667

Total            31437


Правда еще есть Lisp, который еще более компактен, но он, согласитесь, уже относится немного к другому классу языков программирования.
Re[2]: Снова D: Зверёк читает мануал
От: bkat  
Дата: 03.05.05 12:07
Оценка: 12 (1) :))) :))
Здравствуйте, Mamut, Вы писали:

M>[offtop]

M>На смену волне Обероновой пришла волна D
M>[/offtop]

Ты выпустил джина из голубой бутылки.
Re[2]: Снова D: Зверёк читает мануал
От: Зверёк Харьковский  
Дата: 03.05.05 12:45
Оценка:
Здравствуйте, eao197, Вы писали:

ЗХ>>Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.


E>Вот именно. В C++ мне время от времени приходится использовать в качестве ключей в map объекты, содержащие несколько полей:

E>
E>struct    Compound_Key
E>{
E>    Some_Key_Type    a_;
E>    Another_Key_Type    b_;
E>};
E>

E>Так вот в C++ мне достаточно определить только оператор "строго меньше"...

...что, по сути, является определением совсем другого оператора — оператора порядка, а не оператора сравнения. Ты не застрахован от удивления в клиентском коде, когда
Compound_Key a, b;
if(a < b) //так можно
if(a > b) //а так почему-то нельзя :(


Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[2]: Снова D: Зверёк читает мануал
От: Зверёк Харьковский  
Дата: 03.05.05 12:45
Оценка:
Здравствуйте, Mamut, Вы писали:

M>[offtop]


M>На смену волне Обероновой пришла волна D

Ну я вроде стался быть конструктивен. Думал, эта информация будет интересна.

Цель этого мне видится не в ознакомлении всего РСДНа с новым языком — а в обсуждении новых или не очень концепций D и их реализации.
(с) я.


Не интересно — повешай бомбочку

M>[/offtop]
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[3]: Снова D: Зверёк читает мануал
От: Зверёк Харьковский  
Дата: 03.05.05 12:45
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Обероны компактнее.


СГ>Если сложить полные описания всех более-менее известных оберонов, то, думается, описание языка D все равно будет больше их в несколько раз


Но является ли это однозначным преимуществом языка (в ущерб, скажем, выразительности) — вопрос глубоко спорный...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[3]: Снова D: Зверёк читает мануал
От: Mamut Швеция http://dmitriid.com
Дата: 03.05.05 12:54
Оценка:
M>>[offtop]

M>>На смену волне Обероновой пришла волна D


ЗХ>Не интересно — повешай бомбочку


M>>[/offtop]


Да что я. Я ж честно сказал — оффтоп. Это я так... Дядя Зверек, я ж не хотел. А я вместо бомбочки оценку повесил
... << RSDN@Home 1.1.4 beta 6 rev. 433>>


dmitriid.comGitHubLinkedIn
Re[3]: Снова D: Зверёк читает мануал
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.05.05 13:42
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>Здравствуйте, eao197, Вы писали:


ЗХ>>>Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.


E>>Вот именно. В C++ мне время от времени приходится использовать в качестве ключей в map объекты, содержащие несколько полей:

E>>
E>>struct    Compound_Key
E>>{
E>>    Some_Key_Type    a_;
E>>    Another_Key_Type    b_;
E>>};
E>>

E>>Так вот в C++ мне достаточно определить только оператор "строго меньше"...

ЗХ>...что, по сути, является определением совсем другого оператора — оператора порядка, а не оператора сравнения. Ты не застрахован от удивления в клиентском коде, когда

ЗХ>
ЗХ>Compound_Key a, b;
ЗХ>if(a < b) //так можно
ЗХ>if(a > b) //а так почему-то нельзя :(
ЗХ>


ЗХ>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<


Вообще-то я не думаю, что сравнение объектов, которые используются в качестве ключа map-а бессмыслено. Ведь в std::map ключи элементов как раз-таки сравниваются

А пример мой был к тому, что если в C++ мне потребуется сделать класс, от которого средства языка (std::{multi}map, std::{multi}set, std::find, ...) требуют только наличия operator<(), то я и реализую только это. И если от моего класса начинают требовать чего-то еще, то тут же получают по рукам.

В подходе же с opCmp я уже не могу просто сделать сравнение на "строго меньше". Мне в любом случае придется предоставлять варианты для случаев "равно" и "строго больше" (либо чесно их реализуя, либо используя что-то типа: Re: Снова D: Зверёк читает мануал
Автор: WolfHound
Дата: 03.05.05
). И если я по своей лени в D напишу что-то подобное:
class    Compound_Key
{
    int    opCmp( Compound_Key o )
    {
        if( a_ < o.a_ || ( a_ == o.a_ && b_ < o.b_ ) )
            return -1;
        // Оптимистично предполагаем, что всегда будет использоваться (c1<c2).
        return 0;
    }
};

то приведенная тобой конструкция (if(a>b)) на этапе компиляции вообще ошибки не диагностирует.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.