Re[4]: Inline records
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 14.10.09 21:02
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

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


VD>>Речь идет об включении в описание функции имен этих отдельных значений.

VD>>А луа это динамически типизированный скрип в котором даже понятия такого как описание типа нет.

KV>Стало интересно, как это может выглядеть на упомянутом выше netch80 питоне. Как-то так:


Между прочим, в стандартной библиотеке подобные "примочки" уже есть. А именно: os.stat(), os.lstat() возвращают объект, который при обращении к нему как sequence ведёт себя как кортеж на 10 значений, а как к объекту — выдаёт их как поля. (В отличие от Вашего кода, его генерация сделана на C, так что показательный результат не будет.)
The God is real, unless declared integer.
Re[5]: Inline records
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 15.10.09 00:05
Оценка:
Здравствуйте, VladD2, Вы писали:

KV>>Стало интересно, как это может выглядеть на упомянутом выше netch80 питоне. Как-то так:...


VD>Ну, так выходит, что речь идет не о типах, а о некоторой метапрограмме которая переписывает код.


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

Я так понимаю, тебя смутили две вещи:

1. упоминание метакласса в определении ident — этот класс вообще можно смело выкинуть, он используется только для того, чтобы декларировать имена элементов кортежа не строкой, а выражением типа ident.<имя_элемента>. Т.е. если его вообще убрать, то единственное что изменится, это список аргументов у декоратора returnsnames, он станет таким:

@returnsnames('topicid', 'title', 'author')
def getmessage():
    return (3564395, 'Inline records', 'VladD2')


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

2. то, что переменные экземпляра класса со значениями элементов кортежа добавляются в экземпляр "на лету". Но это и есть pythonic-way создания экземплярных переменных — только через их инициализацию. Т.е. если нам нужен класс А, экземпляр которого будет иметь два публичных поля x и y, то единственный способ обеспечить это, такой:

class A:
    def __init__(self):
        self.x = 0
        self.y = 'bla-bla-bla'


Где __init__() — инициализатор экземпляра, который дергается автоматически интерпретатором срауз после инстанцирования класса.

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

a = A()
a.x += a.y


т.к. в инициализаторе для A().x уже был выведен тип int, оператор сложения которого не умеет принимать строку в качестве правого аргумента, для A().y был выведен тип str, а неявные преобразования типов — это php-way, а не питона.

Если интересно, вот тут
Автор: kochetkov.vladimir
Дата: 13.10.09
я набросал тот интерпретатор арифметических выражений из твоей статьи. Там динамизм питона используется в полный рост

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[5]: Inline records
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 15.10.09 00:05
Оценка: 59 (2)
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, kochetkov.vladimir, Вы писали:

VD>Кстати, можно пояснить (прямо по кускам разобрать и прокоментировать) код:

Да, конечно. Правда в процитированном тобой коде я дважды ошибся (один раз — фатально ), поэтому ниже — немного исправленный/дополненный вариант и целиком, ок?

Определяем новый тип inlinerecord, наследуемый от стандартного типа tuple (простой кортеж):
class inlinerecord(tuple):


__new__ — это конструктор экземпляра класса, он дергается интерпретатором автоматически, при каждом инстанцировании. В cls — передается сссылка на инстанцируемый класс (подставляется автоматически, интерпретатором), dict- обычный аргумент конструктора класса:
    def __new__(cls, dict):


Находим своего родителя и дергаем его конструктор для получения ссылки на вновь созданный экземпляр:
        instance = super(inlinerecord, cls).__new__(cls, dict.values())


Сохраняем имена полей записи из словаря в экземплярную переменную names. instance.__dict__ — это внутренний словарь пространства имен нашего экземпляра, т.е. это то же можно было записать как instance.names = tuple(dict.keys()), но в данном случае так нельзя. Почему — см. ниже:
        instance.__dict__['names'] = tuple(dict.keys())


Перебираем все пары значений из словаря с именами/значениями, разворачивая их в name и value и для каждой пары создаем экземплярную переменную ссоответствующим именем и значением:
        for name, value in dict.iteritems(): instance.__dict__[name] = value


Возвращаем созданный экземпляр класса inlinerecord (это ответ на один из твоих вопросов):
        return instance


__setattr__ автоматически дергается интерпретатором при попытке изменить или создать атрибут экземпляра. Выбрасывая тут исключение, мы тем самым запрещаем какую-либо модификацию нашего экземпляра. Именно поэтому в конструкторе приходится использовать прямую запись в пространство имен, а не кошерный способ:
    def __setattr__(self, *args):
        raise TypeError("can't modify immutable instance")


То же, но с удалением атрибутов:
    __delattr__ = __setattr__


__eq__ дергается интерпретатором когда наш экземпляр сравнивается (мы переопределили оператор "==", по сути) с другим объектом на предмет равенства. Возвращаем истину если их типы совпадают и у них одинаковые пары "имя:значение", в противном случае, возвращаем ложь:
    def __eq__(self, other):
        return False if type(other) is not type(self) else self.names == other.names and super(inlinerecord, self).__eq__(other)


VD>Как я понимаю в питоне уже есть тип record?

VD>Именно он возвращается?

Нет, по крайне мере, в стандартной библиотеке record'а нет. В коде возвращался созданный экземпляр класса inlinerecord.

VD>Ну, и поддерживается ли для типа record (если он существует) структурная идентичность? Ну, когда две независимо созданные записи идентичны при условии, что идентичны значения и имена полей.


Во втором варианте кода — да, поддерживается:

a = inlinerecord({'a': 0, 'b': 1})
b = inlinerecord({'a': 0, 'b': 1})
c = inlinerecord({'c': 0, 'b': 1})

print a.a, a.b
print b.a, b.b
print c.c, c.b

print a == b
print b == c
print a == c


Получаем

0 1
0 1

0 1
True
False
False


[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[6]: Inline records
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 15.10.09 00:10
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

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


VD>>Здравствуйте, kochetkov.vladimir, Вы писали:

VD>>Кстати, можно пояснить (прямо по кускам разобрать и прокоментировать) код:

KV>Да, конечно. Правда в процитированном тобой коде я дважды ошибся (один раз — фатально ), поэтому ниже — немного исправленный/дополненный вариант и целиком, ок?


И он же без комментов:
class inlinerecord(tuple):
    def __new__(cls, dict):
        instance = super(inlinerecord, cls).__new__(cls, dict.values())
        instance.__dict__['names'] = tuple(dict.keys())
        for name, value in dict.iteritems(): instance.__dict__[name] = value
        return instance

    def __setattr__(self, *args):
        raise TypeError("can't modify immutable instance")
    __delattr__ = __setattr__

    def __eq__(self, other):
        return False if type(other) is not type(self) else self.names == other.names and super(inlinerecord, self).__eq__(other)

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[13]: Inline records
От: Pavel Dvorkin Россия  
Дата: 15.10.09 02:05
Оценка: -1
Здравствуйте, VladD2, Вы писали:


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


PD>>Инкапсулирование. На С практически невозможно, разве что пародия.


VD>Да, ну? Иди попробуй нарушить инкапсуляцию Win API.


Что за чепуха ? Ты спросил — зачем мне С++, почему не остаться на С. Я ответил — в С++ есть инкапсуляция, а в С нет. При чем тут WinAPI ?

PD>>Наследование. То же.


VD>Да, ну. Это просто сахар же. Реализуется вручную только дат.


Во-первых, я последнюю фразу не понял.

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

Вот тебе

struct POINT {
int x, y;
};

и сделай мне трехмерную точку. Из нее. Без наследования, на чистом С. А я попробую откомпилировать.


PD>>Полиморфизм. То же.


VD>Та же фигня.


Ну-ну. Реализуй, пожалуйста, вручную dynamic_cast на чистом С, сначала, конечно, сделай все же наследование.

VD>Ну, или тебе придется признать, что точно так же в языке нужны и иные расширения упрощающие жизнь.


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

VD>Если ты еще не понял, то разговоры на тему зачем нужны кортежи ничем не отличаются от разговоров на тему зачем нужны классы. Просто ты предвзято относишься к проблеме.


Нет. Классы добавляют мне то, на что я потрачу десятки часов , чтобы реализовать вручную. А возврат кортежа — я могу на 99.9% сделать то же самое через выходные параметры
With best regards
Pavel Dvorkin
Re[29]: доведение ad absurdum
От: Pavel Dvorkin Россия  
Дата: 15.10.09 02:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:

PD>>Демагогия. Никто ничего зловредного не обсуждал.
S>Цитирую:
S>

Linked2List reverseList = Linked2List(Array(sourceList));

S>Кто это написал? Я что ли? Весь смысл этой программы — не дать компилятору её соптимизировать.

Еще раз для не понимающих или не желающих понять. Это — демонстрация того, что можно сделать с твоим подходом.

S>>>Ты можешь писать сколько угодно примеров идиотского кода, который занимается нагреванием воздуха.

PD>>Демагогия.
S>Опять цитирую:
S>

Linked2List reverseList = Linked2List(Array(sourceList));

S>Этот код занимается нагреванием воздуха.

Опять демагогия. Свое дело он делает, то есть переворачивает список.

Кстати, если уж на то пошло — это фактически в иной упаковке ваша любимая сериализация Правда, не в поток, а в массив.

S>>>а) написать много лишнего кода, который всё равно выкинет компилятор

PD>>Не было.
S>Цитирую:
S>
S>IPoint ip;
S>GetPointByRef(ip);
S>FPoint fp1 = ip;
S>FPoint3D fp3D = fp1;
S>

S>Весь лишний код будет устранён компилятором (если не предпринимать специальных усилий).

Опять ложь. Здесь два конструктора. И будет ли их код устранен или нет — зависит от того, что там есть.


S>>>б) написать много лишнего кода, который бы всё равно был выкинут компилятором, и выкинуть его вручную

PD>>Не было. Я как раз предлагал его не писать.
S>Цитирую:
S>

А вот если бы я написал

S>

S>IPoint ip;
S>GetPointByRef(ip);
S>FPoint fp1 = ip;
S>FPoint3D fp3D = fp1;
S>


S>то я бы сразу задал себе вопрос — зачем я тут ерундой занимаюсь!

S>
S>IPoint ip;
S>GetPointByRef(ip);
S>FPoint3D fp3D = ip;
S>

S>Самостоятельно написал лишнюю конверсию IPoint->FPoint->FPoint3d, самостоятельно её выбросил.

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

S>>>в) написать много лишнего кода, который компилятор не сможет выкинуть

PD>>Тоже ложь. Я как раз и предлагал его не писать.
S>Цитирую:
S>
S>Linked2List reverseList = Linked2List(Array(sourceList));
S>

S>Вот этот Array — он здесь зачем? Ясно: для доказательства того, что компилятор не может его выбросить. Здесь нет ни одного неявного преобразования, зато есть явная инструкция "делай медленно".

Ну и ну! Чего-чего, а уж этого я от тебя не ждал.

Здесь вообще никаких инструкций типа "делай медленно" компилятору нет. Инструкции есть в конструкторах (или других методах), а здесь мы видим лишь вызовы их. Доказывается это совершенно элементарно :

Откуда тебе известно, что Array — это массив ? Ты этот вывод из строки

Linked2List reverseList = Linked2List(Array(sourceList));

сделал ? А на каком основании ? Потому что имя класса Array ?

А вдруг этот класс Array вовсе никакого массива и не содержит ? А содержит он только указатель на Linked2List. Конструктор Array по Linked2List просто этот указатель к себе записывает, а конструктор Linked2List по Array переворачивает входной список из Array и берет его к себе! И никакого массива вовсе нет!!! И будет быстро.

Ну и как ?

S>>>г) написать много лишнего кода, который компилятор не сможет выкинуть, и выкинуть его вручную.

PD>>и опять ложь.
S>Снова цитирую:
S>

S>а их конкатенация применительно к данной задаче — абсурдна. Потому что задача решается намного проще. Без всякого выкладывания в массив.

S>То есть сам написал выкладывание в массив, и сам же талантливо от него избавился. Браво, аплодирую стоя.

Аплодируй. Тебе больше ничего и не остается

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

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

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

S>а) редкость (мы всё ещё ждем от мега-гуру плюсов убедительного примера )

Да уж какие еще тебе примеры приводить. Хватит и тех, что были.
With best regards
Pavel Dvorkin
Re[14]: Inline records
От: Pavel Dvorkin Россия  
Дата: 15.10.09 03:28
Оценка:
Здравствуйте, netch80, Вы писали:

N>Вот тут +100. Наличие механизма, упрощающего написание и понимание типичных конструкций, всегда полезно.


При условии. что при этом не нарушается бритва Оккама.
With best regards
Pavel Dvorkin
Re[15]: Inline records
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 15.10.09 06:04
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


N>>Вот тут +100. Наличие механизма, упрощающего написание и понимание типичных конструкций, всегда полезно.


PD>При условии. что при этом не нарушается бритва Оккама.


А вот с этим надо осторожнее. Потому что бритвой Оккама можно слишком многое отрезать. Как тебе вариант, когда операция вычитания отменена потому, что есть инверсия знака и вместо a-b можно всегда написать a+(-b)? И почему ни один распространённый язык программирования такого не требует — даже Форт, где для такой операции не нужны скобки?

Или — зачем нужны многомерные массивы? Всё ведь можно не хуже сделать в одномерных:))

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

Поэтому, если возражать против предложения, начавшего эту дискуссию — то только на основании противоречивости будущим направлениям развития языка. И я тут на 101% полагаюсь на VladD2 — он по-любому сможет оценить этот фактор лучше прочих участников треда.

А в общем случае — да, можно и Оккамом помахать:) вместо веера:))
The God is real, unless declared integer.
Re[14]: Inline records
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 15.10.09 06:29
Оценка: +3
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вот тебе


PD>struct POINT {

PD> int x, y;
PD>};

PD>и сделай мне трехмерную точку. Из нее. Без наследования, на чистом С. А я попробую откомпилировать.


struct POINT3D {
  struct POINT plain;
  int z;
};

В документации пишем, что к элементам надо обращаться не x, y, z, а plain.x, plain.y, z.

Quod erat demonstrandum.

Этот приём систематически применяется, например, в GTK и GLib. Там сделана иерархия структур "объектов" интерфейса (местами до 5 уровней!) вложением структур. Для оптимизации доступа вглубь — используется конверсия указателей.

VD>>Если ты еще не понял, то разговоры на тему зачем нужны кортежи ничем не отличаются от разговоров на тему зачем нужны классы. Просто ты предвзято относишься к проблеме.

PD>Нет. Классы добавляют мне то, на что я потрачу десятки часов , чтобы реализовать вручную. А возврат кортежа — я могу на 99.9% сделать то же самое через выходные параметры

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

Разница между кортежом и выходными параметрами именно та, что первое даёт _функциональный_ подход. У тебя есть вход и выход из функции. В случае выходных параметров, если ты им не даёшь предыдущего значения — это ничем не отличается от кортежа, кроме синтаксического неудобства; а если у них уже было значение — это является разрушающим присвоением, который в этом подходе недопустим.
The God is real, unless declared integer.
Re[16]: Inline records
От: Pavel Dvorkin Россия  
Дата: 15.10.09 06:38
Оценка:
Здравствуйте, netch80, Вы писали:

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


С многим можно согласиться. Но вот с этим готов поспорить.

Допустим, VladD2 или кто-то еще оценил непротиворечивость будущему направлению развития и вынес вердикт — не противоречит. Вердикт этот под сомнение ставить не будем, примем как истину. Означает ли это, что можно добавлять ?

ИМХО нет. Язык ведь можно и по принципу языка-оболочки построить. Классический пример — PL/1. Он так и был задуман — взять все хорошее, что есть в Фортране, добавить все хорошее, что есть в Алголе, добавить все хорошее, что есть в Коболе (я не шучу, это именно так и было), получим универсальный язык, который может заменить и Алгол, и Фортран, и Кобол. И это не противоречит будущим направлениям. Понадобилось бы — он и C вместе с C++ в себя бы включил.

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

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

Вот поэтому я за то, чтобы проверять бритвой все нововведения. Конечно, не надо доводить до абсурда. Но все же, если некое нововвдение таково, что оно на 99% может быть реализовано уже имеющимися средствами, то надо 10 раз подумать, стоит ли его добавлять.
With best regards
Pavel Dvorkin
Re[15]: Inline records
От: Pavel Dvorkin Россия  
Дата: 15.10.09 06:52
Оценка:
Здравствуйте, netch80, Вы писали:


PD>>и сделай мне трехмерную точку. Из нее. Без наследования, на чистом С. А я попробую откомпилировать.


N>
N>struct POINT3D {
N>  struct POINT plain;
N>  int z;
N>};
N>


Неужели ты думаешь, что я до такого сам не мог догадаться ?
Только не наследование это в классическом смысле, а наследование включением. Это совсем разные понятия.

N>В документации пишем, что к элементам надо обращаться не x, y, z, а plain.x, plain.y, z.


Замечательная мысль. Поитом еще одного наследника сделаем

struct EinsteinPoint {
struct POINT3D point3D;
int time;
};

и в инструкции напишем, что поля называются point3D.plain.x, point3D.plain.y, point3D.z и почему-то просто time;



Но и не это главное. Как методы наследовать-то будешь ? Пусть невиртуальные, ладно, но как наследовать-то ? В классе POINT3D будешь заново описывать все методы и реализовать их путем вызова соответствующего метода внедренного объекта ? Такое, конечно, имеет право на существование, и применяется, но... хорошенькое наследование, когда я обязан привести заново все методы базового класса!


N>Quod erat demonstrandum.


N>Сравнение некорректно. Ты используешь возможности (такие, как инкапсуляция, наследование...) потому что механизм уже есть. Кто-то уже потратил на это миллионы часов, при этом он сам по себе ничего Оккамом не рубил.


Ничего подобного. Если оставить в стороне виртуальность, то наследование не есть никакой механизм. Это просто требование к компилятору собрать воедино все поля (родителя и мои) и взять из описания родителя его функции и добавить их мне. Вот и все. Но вот это-то я и не могу компилятору С объяснить!
With best regards
Pavel Dvorkin
Re: Inline records
От: Undying Россия  
Дата: 15.10.09 06:53
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А почему бы не рассматривать возвращаемое значение функции так же как набор параметров? При этом синтаксис может быть совершенно разрообразным.

VD>
VD>(string ret1, int ret2) FuncName(string param1, int param2)
VD>


Вообще-то это все полумеры. Т.к. если нам нужно вернуть что-то более сложное, чем набор параметров (например, ключ, что требует перекрытия Equals и GetHashCode), то придется по-прежнему для достижения читабельности писать гору кода, вроде:

class TourKey
{
  public readonly string Name;
  public readonly DateTime BeginTime;
  public TourKey(string name, DateTime beginTime)
  {
    this.Name = name;
    this.BeginTime = beginTime;
  }
  public override bool Equals(object obj)
  {
    ...
  }
  public override int GetHashCode()
  {
    ...
  } 
}

TourKey GetTourKey(Tour tour)
{
  ...
}


Вместо всего этого кошмара хотелось бы такой записи:

class TourKey implement PairedKey<string, DateTime, First as Name, Second as BeginTime>;

TourKey GetTourKey(Tour tour)
{
  ...
}


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

Причем все это достигается за пять копеек, без какой либо переделки CLR, достаточно прекомпилятору строку:

class TourKey implement PairedKey<string, DateTime, First as Name, Second as BeginTime>;


заменять на:

class TourKey
{
  readonly PairedKey<string, DateTime> obj;

  public TourKey(string Name, DateTime BeginTime)
  {
    obj = new PairedKey<string, DateTime>(Name, BeginTime);
  }

  public string Name
  {
    get { return obj.First; }
  }

  public DateTime BeginTime
  {
    get { return obj.Second; }
  }

  public override int GetHashCode()
  {
    return obj.GetHashCode();
  }

  //Имплементация остальных методов PairedKey
}


Также достоинством является, что это решение не требует изменения концепций языка, оно полностью находится в русле понятий C# 2.0 Т.е. такое решение язык усложняет минимально, а новых возможностей добавляет массу.
Re[16]: Inline records
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 15.10.09 07:12
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Неужели ты думаешь, что я до такого сам не мог догадаться ? :-)


При чём тут "мог догадаться"?

PD>Только не наследование это в классическом смысле, а наследование включением. Это совсем разные понятия.


На Си наследование проще всего реализовать через наследование включением.

N>>В документации пишем, что к элементам надо обращаться не x, y, z, а plain.x, plain.y, z.

PD>Замечательная мысль. Поитом еще одного наследника сделаем

PD>struct EinsteinPoint {

PD> struct POINT3D point3D;
PD> int time;
PD>};

PD>и в инструкции напишем, что поля называются point3D.plain.x, point3D.plain.y, point3D.z и почему-то просто time;


Именно! Но согласись, что всё это просто неудобства, а не принципиальная проблема.

PD>:-)

PD>Но и не это главное. Как методы наследовать-то будешь ? Пусть невиртуальные, ладно, но как наследовать-то ? В классе POINT3D будешь заново описывать все методы и реализовать их путем вызова соответствующего метода внедренного объекта ?

Зачем?

struct POINT* p = (struct POINT*) p3d;
return p->getX(p);


PD> Такое, конечно, имеет право на существование, и применяется, но... хорошенькое наследование, когда я обязан привести заново все методы базового класса!


Никто от тебя не требует их "привести заново", не выдумывай:)

N>>Quod erat demonstrandum.

N>>Сравнение некорректно. Ты используешь возможности (такие, как инкапсуляция, наследование...) потому что механизм уже есть. Кто-то уже потратил на это миллионы часов, при этом он сам по себе ничего Оккамом не рубил.
PD>Ничего подобного. Если оставить в стороне виртуальность, то наследование не есть никакой механизм. Это просто требование к компилятору собрать воедино все поля (родителя и мои) и взять из описания родителя его функции и добавить их мне. Вот и все. Но вот это-то я и не могу компилятору С объяснить!

Нет, это не наследование. Это реализация наследования в некоторых распространённых языках вроде C++. Да, типичная — когда определённые в предке имена включаются в плоское пространство имён потомка. Но не единственная, и не требуемая напрямую определением.
The God is real, unless declared integer.
Re[17]: Inline records
От: Pavel Dvorkin Россия  
Дата: 15.10.09 07:31
Оценка:
Здравствуйте, netch80, Вы писали:

N>На Си наследование проще всего реализовать через наследование включением.


Вот поэтому мне и нужен С++, чтобы не заниматься этим включением, а писать как в С++.


N>Именно! Но согласись, что всё это просто неудобства, а не принципиальная проблема.


Не соглашусь.

PD>>

PD>>Но и не это главное. Как методы наследовать-то будешь ? Пусть невиртуальные, ладно, но как наследовать-то ? В классе POINT3D будешь заново описывать все методы и реализовать их путем вызова соответствующего метода внедренного объекта ?

N>Зачем?


N>
N>struct POINT* p = (struct POINT*) p3d;
N>return p->getX(p);
N>


??? Что это за getX, вызываемая по указателю на POINT ??? На чистом С ?

Вот так еще можно

struct POINT* p = (struct POINT*) p3d;
return getX(p); // предполагаю, что есть getX(POINT*);


Но это для первого элемента структуры пройдет. А для следующего ? Будем sizeof'ы добавлять ? А выравнивание как ?

N>Никто от тебя не требует их "привести заново", не выдумывай


OK.

struct POINT {int x,y;};
struct TIME {int hour, minute, second};

// функции для работы с POINT — 10 штук
// функции для работы с TIME — 10 штук

struct TEXT_POINT_TIME
{
char mark;
char* str;
POINT pt;
TIME tm;
};

// функции для работы с mark, str я сам напишу, а вот для работы с полями pt и tm — новые создавать не буду. Скажи, как использовать старые.

TEXT_POINT_TIME tpt;
// и вот здесь хочу вызвать getX(POINT*)

N>Нет, это не наследование. Это реализация наследования в некоторых распространённых языках вроде C++. Да, типичная — когда определённые в предке имена включаются в плоское пространство имён потомка. Но не единственная, и не требуемая напрямую определением.


Вот с этим согласен. Не единственная. Есть и другие варианты, в том числе тот, о котором ты пишешь. Но я-то хочу перейти с С на С++ именно для этого
With best regards
Pavel Dvorkin
Re[5]: Inline records
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 15.10.09 07:38
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>За скалу не скжу, но что-то не помню там синтаксиса для записи записей.


Забей, я про таплы говорил, а не записи.
Re[18]: уточнение
От: Pavel Dvorkin Россия  
Дата: 15.10.09 09:47
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>Вот так еще можно


PD>struct POINT* p = (struct POINT*) p3d;

PD>return getX(p); // предполагаю, что есть getX(POINT*);


PD>Но это для первого элемента структуры пройдет. А для следующего ? Будем sizeof'ы добавлять ? А выравнивание как ?


Вообще-то можно, конечно. Есть такой макрос — offsetof. С его помощью можно получить смещение для любого поля структуры, при любом выравнивании. Так что теоретически задача решается. И даже для функций решается. Но упаси меня бог от такого программирования — это в корне противоречит всем принципам. Я уж не говорю, что в С нет никаких private — protected и придется напрямую копаться в структурах без всякой защиты. Нет уж, только без меня
With best regards
Pavel Dvorkin
Re[17]: Inline records
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 15.10.09 10:02
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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

PD>С многим можно согласиться. Но вот с этим готов поспорить.
PD>Допустим, VladD2 или кто-то еще оценил непротиворечивость будущему направлению развития и вынес вердикт — не противоречит. Вердикт этот под сомнение ставить не будем, примем как истину. Означает ли это, что можно добавлять ?

[skip]

Ты не учёл во всей этой филиппике одну вещь: переусложнение фичами явно будет мешать развитию языка. Поэтому — все подобные "а давайте тут ещё насадим две пришлёпки сбоку" не пройдёт по этому критерию.

Хотя можно, конечно, это всё потом объявить obsoleted и "кто за две версии не переписал — я не виноват..." (шютка)

PD>ИМХО нет. Язык ведь можно и по принципу языка-оболочки построить. Классический пример — PL/1. Он так и был задуман — взять все хорошее, что есть в Фортране, добавить все хорошее, что есть в Алголе, добавить все хорошее, что есть в Коболе (я не шучу, это именно так и было), получим универсальный язык, который может заменить и Алгол, и Фортран, и Кобол. И это не противоречит будущим направлениям. Понадобилось бы — он и C вместе с C++ в себя бы включил.

PD>На первый взгляд ничего плохого. Сложим в кучу все, что есть, а потом пусть каждый программист выбирает из него то, что ему надо. Но не пошла эта концепция. Размывается при этом структура языка. Из чего-то, что имеет некую внутреннюю логику и построено в соответствии с некоей исходной идеей, язык превращается просто в набор всяких и разных фич, введенных не потому, что без них не обойдешься, а потому, что эта новая фича удобна и красива, хотя на 99% и прежними средствами можно было бы сделать то же самое.

А в результате мы до сих пор не имеем распространённого языка, которому бы можно было сказать "вот этот тип — плавающая точка с порядком +/-100 и точностью 10 десятичных разрядов" и он бы это выполнил.

Вы с водой выплёскиваете ребёнка. Кстати, PL/1 был очень простым — проще C++ или Java.

PD>Вот поэтому я за то, чтобы проверять бритвой все нововведения. Конечно, не надо доводить до абсурда. Но все же, если некое нововвдение таково, что оно на 99% может быть реализовано уже имеющимися средствами, то надо 10 раз подумать, стоит ли его добавлять.


У нас какой контекст? Nemerle или C++?
The God is real, unless declared integer.
Re[19]: уточнение
От: samius Япония http://sams-tricks.blogspot.com
Дата: 15.10.09 10:15
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вообще-то можно, конечно. Есть такой макрос — offsetof. С его помощью можно получить смещение для любого поля структуры, при любом выравнивании. Так что теоретически задача решается. И даже для функций решается. Но упаси меня бог от такого программирования — это в корне противоречит всем принципам. Я уж не говорю, что в С нет никаких private — protected и придется напрямую копаться в структурах без всякой защиты. Нет уж, только без меня


Инкапсуляцию можно достичь не только за счет модификаторов видимости. Abstraction Barrier, например поможет. Опять таки модификаторы видимости не являются необходимостью. Это только способ сказать "не суй туда пальцы". А барьеры абстракции — более серьезные механизмы.
Re[18]: Inline records
От: Pavel Dvorkin Россия  
Дата: 15.10.09 10:24
Оценка:
Здравствуйте, netch80, Вы писали:

N>Ты не учёл во всей этой филиппике одну вещь: переусложнение фичами явно будет мешать развитию языка.


Не уверен. PL/1 оно не мешало, пока он фактически сам не помер.

>Поэтому — все подобные "а давайте тут ещё насадим две пришлёпки сбоку" не пройдёт по этому критерию.


Ну дай-то бог. Но ИМХО то, что VladD2 предлагает — если это применить к C# (это мое предположение) — окажется именно такой нашлепкой.

N>Хотя можно, конечно, это всё потом объявить obsoleted и "кто за две версии не переписал — я не виноват..." (шютка)


Элементы языка очень редко объявляют obsolete. Я такого почти не помню, разве что object из ТурбоПаскаля, который заменили на class Дельфи, и описание параметров функции в С по K&R. Функции библиотек — другое дело.

Шутку оценил

N>А в результате мы до сих пор не имеем распространённого языка, которому бы можно было сказать "вот этот тип — плавающая точка с порядком +/-100 и точностью 10 десятичных разрядов" и он бы это выполнил.


Между прочим, в PL/1 как раз можно было указать размер мантиссы и порядка. Но не пошло. Видимо, не так уж нужно.

N>Вы с водой выплёскиваете ребёнка. Кстати, PL/1 был очень простым — проще C++ или Java.


Ну в каком-то смысле да.

PD>>Вот поэтому я за то, чтобы проверять бритвой все нововведения. Конечно, не надо доводить до абсурда. Но все же, если некое нововвдение таково, что оно на 99% может быть реализовано уже имеющимися средствами, то надо 10 раз подумать, стоит ли его добавлять.


N>У нас какой контекст? Nemerle или C++?


Я вроде о Немерле ни слова не говорил... А в С++ такое никогда добавлено не будет, уверен.
With best regards
Pavel Dvorkin
Re[30]: доведение ad absurdum
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.10.09 11:59
Оценка: +1 -1
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Еще раз для не понимающих или не желающих понять. Это — демонстрация того, что можно сделать с твоим подходом.
С моим подходом этого сделать нельзя.

PD>Опять демагогия. Свое дело он делает, то есть переворачивает список.

В коде по прежнему нет ничего про переворачивание списка.

PD>Опять ложь. Здесь два конструктора. И будет ли их код устранен или нет — зависит от того, что там есть.

Если не предпринимать специальных усилий, то код лишнего конструктора будет устранён.

PD>Ну и ну! Чего-чего, а уж этого я от тебя не ждал.


PD>Здесь вообще никаких инструкций типа "делай медленно" компилятору нет. Инструкции есть в конструкторах (или других методах), а здесь мы видим лишь вызовы их.

Да, мы видим принудительный вызов промежуточного метода

PD>Доказывается это совершенно элементарно :


PD>Откуда тебе известно, что Array — это массив ? Ты этот вывод из строки

Из твоего описания. Как я уже говорил, этот код — ужасен, потому что не отражает сути происходящего. Тебе процитировать описание метода, которым ты его сопроводил, или самостоятельно найдёшь?

PD>А вдруг этот класс Array вовсе никакого массива и не содержит ? А содержит он только указатель на Linked2List. Конструктор Array по Linked2List просто этот указатель к себе записывает, а конструктор Linked2List по Array переворачивает входной список из Array и берет его к себе! И никакого массива вовсе нет!!! И будет быстро.

PD>Ну и как ?
Отлично. По прежнему разработчик такого кода — кандидат на увольнение. Потому что метод с именем Array не должен заниматься реверсом списка. Ни быстрым, ни медленным.

PD>Да уж какие еще тебе примеры приводить. Хватит и тех, что были.

То есть ты не в состоянии продемонстрировать пример неявного преобразования, который бы иллюстрировал хоть какие-то проблемы.
Ок, ничего другого я и не ожидал.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.