Re[3]: [Динамик не нужен] Анонимные алгебраические типы.
От: artelk  
Дата: 28.04.11 09:20
Оценка:
Здравствуйте, dotneter, Вы писали:

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


D>Вроде все тоже самое, можно было остановится на


A>>let bar i = i + 1

A>>let bar s = s + "\n"

D>bar :: int | string -> int | string


D>Тут же как раз работает матчинг по типу.


Ага. Но разные bar могут лежать в разных "сборках".
Именно такой тип конструируется для bar, хотя, например, "bar 1" все еще должен вернуть int, а не анонимный int|string.
Если оба типа принадлежат одному классу типов, то тоже можно было бы создавать такой bar по месту:
class Plusable a where
  (+) :: a -> a -> b

instance Plusable Int where
  ...
instance Plusable String where
  ...

bar :: (Plusable a) => a -> a -> a
let bar (Plusable x) = x + x + x

let z1 = bar x1
z1 :: int | string


ЗЫ (С) Слабо-сильно типизированный язык программирования
Re: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 28.04.11 18:12
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Давече господину Воронкову Василию был задан вопрос, зачем нужен динамик.

D>Что бы возвращать разные типы из функции в записимости от входящих параметров, отвечает он.

Исходный пример я пропустил. Он мне не нравится. Предлагаю более интересный вариант (из практики):
public static function exceptionProtect(f : Function, exnHandler : Function) : Function {
  return function(...args) : * {
    try {
      return f.applly(null, args);
    } catch (e : *) {
      exnHandler(e);
      throw e;
    }
  }
}

Эта функция принимает функцию (с произвольным числом и типом аргументов, более точной типизации функций в языке нет) и возвращает функцию, которая добавляет дополнительный уровень обработки исключений. Для всех возникших в f исключений вызывается exnHandler и исключение пробрасывается дальше. Работает для всех функций — с любым числом и типами аргументов, корректно работает с опциональными параметрами. Вопрос: а как оно будет выглядеть в вашем статически типизированном решении?

D>Я предлагаю статически типизированое решение, что то похожее на

D>
D>let foo x = if x == 0 then 0 else "bar" end
D>foo :: int -> int | string
D>

А что именно даст статическая типизация? Она будет только для проверки "корректности" кода или еще как-то использоваться в процессе компиляции?

D>Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.

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

Вообще, сама идея здравая. Но для этого рантайм должен позволять делать нетривиальные вещи. Например, создавать новые типы (классы), вызывать в обобщенной форме функции и т.п. В этом случае "обобщенные" функции могут как-то преобразовывать тип своих аргументов. Что-то вроде недомакросов но при этом в рантайме. Тогда тип результата будет нетривиальным образом зависеть от типов (возможно — и значений) входных параметров. Ну и для проверки корректности, естественно, хотелось бы вычислять типы результатов вызова таких функций (или еще какую-либо информацию).
Re[2]: Анонимные алгебраические типы. Более сложный случай.
От: dotneter  
Дата: 28.04.11 18:41
Оценка:
Здравствуйте, maxkar, Вы писали:


M>Эта функция принимает функцию (с произвольным числом и типом аргументов, более точной типизации функций в языке нет) и возвращает функцию, которая добавляет дополнительный уровень обработки исключений. Для всех возникших в f исключений вызывается exnHandler и исключение пробрасывается дальше. Работает для всех функций — с любым числом и типами аргументов, корректно работает с опциональными параметрами. Вопрос: а как оно будет выглядеть в вашем статически типизированном решении?

Вам тут нужен макрос, а не статическая типизация.


D>>Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.

M>Идея интересная. Применительно к динамике я бы еще хотел возможность написать код, вычисляющий тип результата (и выполняющий некоторые проверки) для функции и выполняющийся по каждому метсу вызова. Например, для приведенного мной примера я могу сказать, что именно получится в результате. Более того, все получающиеся преобразования типов в своем коде (на данный момент) я могу описать зная типы исходных аргументов. Если позволить читать внешние метаданные, я могу проверить вообще все типы в программе (часть динамики управляется внешним конфигом в рантайме).

M>Вообще, сама идея здравая. Но для этого рантайм должен позволять делать нетривиальные вещи. Например, создавать новые типы (классы), вызывать в обобщенной форме функции и т.п. В этом случае "обобщенные" функции могут как-то преобразовывать тип своих аргументов. Что-то вроде недомакросов но при этом в рантайме. Тогда тип результата будет нетривиальным образом зависеть от типов (возможно — и значений) входных параметров. Ну и для проверки корректности, естественно, хотелось бы вычислять типы результатов вызова таких функций (или еще какую-либо информацию).

Этот поток сознания я не осилил, но похоже вы опять про макросы.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[4]: [Динамик не нужен] Анонимные алгебраические типы.
От: dimgel Россия https://github.com/dimgel
Дата: 28.04.11 23:04
Оценка:
Здравствуйте, Temoto, Вы писали:

D>>
D>>let x =
D>>    match x with
D>>    | :? Int as y -> print "is int"
D>>    | :? String as y -> print "is string"
D>>


T>Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.


В динамике практически то же самое, если со возвращённым значением предполагается делать что-либо посложнее, чем тупо вывести его в строку:

if (is_int($x)) {
   exit($x);
} else {
   // do something with string $x
}
Re[3]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 29.04.11 08:18
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Вам тут нужен макрос, а не статическая типизация.


Зачем это мне здесь нужен макрос? Почему вы решили, что я хочу во время компиляции генерировать какой-то код, а не в рантайме в динамике оборачивать функцию? Тем более что в коде эта функция используется в том контексте, в котором макросы не помогут. Ей на вход кормится страшная функция, собираемая по внешнему конфигу. Исходная функция — interop между всеми модулями приложения и заодно repository, из которого модули получают необходимые им сервисы. Ну а обертка — фактически, одна простая и короткая возможность вывести пользователю "правильные" сообщения об ошибке если что-то пошло не так. Ну и что можно макросом здесь сделать? А вот написать правила преобразования типов этой функцией я вполне мог бы.
Re[4]: Анонимные алгебраические типы. Более сложный случай.
От: dotneter  
Дата: 29.04.11 08:39
Оценка:
Здравствуйте, maxkar, Вы писали:

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


D>>Вам тут нужен макрос, а не статическая типизация.


M>Зачем это мне здесь нужен макрос? Почему вы решили, что я хочу во время компиляции генерировать какой-то код, а не в рантайме в динамике оборачивать функцию?

Я решил что вам нужен статически типизированый врапер для функции, это задача кодогенерации, значит нужен макрос
Я не знаю что у вас там за конструктор страшны функции, но если у вас есть функция
void Foo(){DoSomething()}


То с помощью кодогеренации можно сделать врапер, хоть так
void Foo() { try DoSomething catch }


хоть так
Action GetWraper(Action x){
  return () => {try DoSomething catch}
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 11:24
Оценка:
Здравствуйте, dotneter, Вы писали:

Ты все перевернул с ног на голову.

Есть два варианта:
+ Функция, тип которой зависит от [типа] параметров
+ Функция, тип которой зависит от значений параметров

Первый вариант в статике возможен:

printf "%d+%d=%d" 2 2 (2+2)

Второй — нет:

let myPrint fmt = printf fmt ...?

То, что ты приводишь:

def foo(x): if x == 0 then 0 else "bar" end

Судя по твоему описанию абсолютно равносильно:

data Either a b = Left a | Right b
foo x | x == 0 = Left 0
| otherwise = Right "bar"

Тип функции foo при этом — Either. Этот тип вообще никак не зависит от параметров. Аналогичная ф-ция foo в динамике:

let foo x | x == 0 = 0
| else = "bar"

Имеет тип, зависящий от *значения* х. Поэтому код вида:

foo 0 * foo 0

верный и отработает. Но код:

foo 0 * foo 1

неверный и свалится в рантайме.

Системы типов консервативны, они не пытаются доказать правильность программы, они доказывают ее возможную неправильность. Код вида foo x * foo y возможно неправильный (но частный случай foo 0 * foo 0 — правильный). Исходя из того, что выражение foo x * foo y в принципе может быть неправильным, система типов этот код не пропустит.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 11:26
Оценка:
Здравствуйте, WolfHound, Вы писали:

D>>плюс мне видится это это вполне реализуемое как сахар поверх какого нибудь

WH>Вполне себе вариант.
WH>правда и сигнатуру функции тогда уж описывать так
WH>
WH>foo :: int -> X int | Y string
WH>let foo x = if x == 0 then X 0 else Y "bar" end
WH>


Тип этой функции не зависит от значений параметров. Тип *всегда* int|string.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 11:45
Оценка:
Здравствуйте, Воронков Василий, Вы писали:


ВВ>data Either a b = Left a | Right b

ВВ>foo x | x == 0 = Left 0
ВВ> | otherwise = Right "bar"
Да, разве что без надобности вводить тип.

ВВ>Тип функции foo при этом — Either. Этот тип вообще никак не зависит от параметров. Аналогичная ф-ция foo в динамике:

Да, но решает туже задачу.

ВВ>let foo x | x == 0 = 0

ВВ> | else = "bar"

ВВ>Имеет тип, зависящий от *значения* х. Поэтому код вида:


ВВ>foo 0 * foo 0


ВВ>верный и отработает. Но код:


ВВ>foo 0 * foo 1


ВВ>неверный и свалится в рантайме.

Суть как раз в том что в статике ничего не свалится, компилятор не даст.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[3]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 13:43
Оценка:
Здравствуйте, dotneter, Вы писали:

ВВ>>data Either a b = Left a | Right b

ВВ>>foo x | x == 0 = Left 0
ВВ>> | otherwise = Right "bar"
D>Да, разве что без надобности вводить тип.

Без надобности, да. Вот только если тип не вводить, то все автоматически объявляемые конструкторы будут принадлежать одному типу. И тип функции

foo x = if x == 0 then 0 else "bar"


будет точно такой же, как и у

bar x = if x == 0 then 42.42 else 'b'


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

Собственно, есть мнение, что динамика — это статика, в которой есть лишь один-единственный тип.

ВВ>>Тип функции foo при этом — Either. Этот тип вообще никак не зависит от параметров. Аналогичная ф-ция foo в динамике:

D>Да, но решает туже задачу.

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

ВВ>>неверный и свалится в рантайме.

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

Да, потому что в статике компилятор просто не скомпилирует эквивалетный код.
Re[5]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 13:45
Оценка:
Здравствуйте, dimgel, Вы писали:

T>>Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.


D>В динамике практически то же самое, если со возвращённым значением предполагается делать что-либо посложнее, чем тупо вывести его в строку:


Нет, не то же самое. В динамике будет утиная типизация.
Re[2]: Анонимные алгебраические типы. Более сложный случай.
От: FR  
Дата: 29.04.11 13:47
Оценка: 14 (2)
Здравствуйте, maxkar, Вы писали:

M>Исходный пример я пропустил. Он мне не нравится. Предлагаю более интересный вариант (из практики):

M>
M>public static function exceptionProtect(f : Function, exnHandler : Function) : Function {
M>  return function(...args) : * {
M>    try {
M>      return f.applly(null, args);
M>    } catch (e : *) {
M>      exnHandler(e);
M>      throw e;
M>    }
M>  }
M>}
M>

M>Эта функция принимает функцию (с произвольным числом и типом аргументов, более точной типизации функций в языке нет) и возвращает функцию, которая добавляет дополнительный уровень обработки исключений. Для всех возникших в f исключений вызывается exnHandler и исключение пробрасывается дальше. Работает для всех функций — с любым числом и типами аргументов, корректно работает с опциональными параметрами. Вопрос: а как оно будет выглядеть в вашем статически типизированном решении?

Если в языке достаточно развитое метапрограммирование будет выглядеть вполне прилично, вот например вариант на шаблонах D:

import std.traits;
import std.conv;
import std.stdio;


template ExceptionProtect(alias Fun, alias ExnHandler)
{
    ReturnType!Fun ExceptionProtect(ParameterTypeTuple!Fun args)
    {
    ReturnType!Fun Result;
    
    try{
        Result = Fun(args);
        }    
    catch(Exception e){
        ExnHandler(e);
        throw e;
        }
    
    return Result;
    }    
}


string TestInc(int i)
{
    if(i > 0)
        return text("Ok result = ", i + 1);
    else
        throw new Exception("TestInc() failed");
    
    return "Fail";
}


void TestExnHandler(Exception e)
{
    writeln("TestExnHandler run");
}

void main()
{
    writeln(ExceptionProtect!(TestInc, TestExnHandler)(123));
    writeln(ExceptionProtect!(TestInc, TestExnHandler)(-1));
}
Re[6]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:19
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


T>>>Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.


D>>В динамике практически то же самое, если со возвращённым значением предполагается делать что-либо посложнее, чем тупо вывести его в строку:


ВВ>Нет, не то же самое. В динамике будет утиная типизация.

Чем вас не устраивает структурная?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[4]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:19
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>
ВВ>foo x = if x == 0 then 0 else "bar"
ВВ>


ВВ>будет точно такой же, как и у


ВВ>
ВВ>bar x = if x == 0 then 42.42 else 'b'
ВВ>

Почему такой же? int|string double|string

ВВ>Этот код ты сам придумал, и я знаю, какую задачу он решает. Я приводил другие примеры, и на статике они не выражаются.

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

ВВ>>>неверный и свалится в рантайме.

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

ВВ>Да, потому что в статике компилятор просто не скомпилирует эквивалетный код.

Не скомпилирует он только то что нельзя с полной увереностью сказать сработает при всех возможных сочетаниях типов.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[7]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 14:28
Оценка: +1
Здравствуйте, dotneter, Вы писали:

ВВ>>Нет, не то же самое. В динамике будет утиная типизация.

D>Чем вас не устраивает структурная?

Структурная работает только если типы выводятся.
Re[5]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 14:31
Оценка:
Здравствуйте, dotneter, Вы писали:

ВВ>>
ВВ>>bar x = if x == 0 then 42.42 else 'b'
ВВ>>

D>Почему такой же? int|string double|string

Т.е. я не смогу написать одну полиморфную функцию, которая будет анализировать результат возвращаемый под видом int|string или double|string?
И кстати, как вообще анализировать тип? Как проверить, что функция вернула строку или число?

ВВ>>Этот код ты сам придумал, и я знаю, какую задачу он решает. Я приводил другие примеры, и на статике они не выражаются.

D>Можете привести пример еще раз, но что бы он не пытался взорвать мозг, и максимально просто отражал то что вы хотите.

Скажи, что тебе конкретно взрывает мозг, и я попробую упростить пример именно в этом месте.
Re[8]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:52
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


ВВ>>>Нет, не то же самое. В динамике будет утиная типизация.

D>>Чем вас не устраивает структурная?

ВВ>Структурная работает только если типы выводятся.

И? Ну и пусть выводятся.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[6]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:52
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


ВВ>>>
ВВ>>>bar x = if x == 0 then 42.42 else 'b'
ВВ>>>

D>>Почему такой же? int|string double|string

ВВ>Т.е. я не смогу написать одну полиморфную функцию, которая будет анализировать результат возвращаемый под видом int|string или double|string?

Можете :: (Num a) => a|string ->
ВВ>И кстати, как вообще анализировать тип? Как проверить, что функция вернула строку или число?
Вы же в той ветке отвечали
http://rsdn.ru/forum/philosophy/4251489.1.aspx
Автор: dotneter
Дата: 27.04.11

или так
bar x :: int ->
bar x :: string ->

ВВ>>>Этот код ты сам придумал, и я знаю, какую задачу он решает. Я приводил другие примеры, и на статике они не выражаются.

D>>Можете привести пример еще раз, но что бы он не пытался взорвать мозг, и максимально просто отражал то что вы хотите.

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

let fun (x::xs) = fun' x xs
where fun' a [] = \y -> y + a
fun' a (x::xs) = \y -> fun' (y + a + x) xs
Обязательно нужно работать со списками, и в обоих случаях возвращать функции, проще ничего не придумать?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[3]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 29.04.11 14:56
Оценка:
Здравствуйте, FR, Вы писали:

FR>Если в языке достаточно развитое метапрограммирование будет выглядеть вполне прилично, вот например вариант на шаблонах D:


Да, неплохо. Только вот мне не нравится, что это шаблон. Я хочу именно функцию. Чтобы ее можно было куда-нибудь еще передавать, например. Я не против писать то, что в шаблоне написано, это позволит проверить типы там, где они известны на этапе компиляции. А там, где функция используется на динамике, пусть работает в "моем" варианте. Более того, пусть "статические" вызовы компилятор инлайнит, но динамика все равно остается. Потому что изначально метод предназначался для защиты функции, строящейся по конфигу во время исполнения, а не во время написания кода. Что-то вроде
const cls : Class = findClass(config.confClass);
const instance : Object = new Class();
const func = instance[config.confMethod];
return exceptoinProtect(func, protector);


Более того, на основе этой же функции я могу, например, защищать "интерфейсы":
function protectInterface(iface : Object, protector : Function) : Object {
  const res : Object = {};
  for (var item : String in iface) {
    var val : Object = iface[item];
    var valf : Function = val as Function;
    res[item] = valf != null ? exceptionProtect(valf, protector) : val;
  }  
  return res;
}

Оно строит новый объект, имеющий те же поля (с теми же значениями) но функции обернуты и защищены. Полезно на инфраструктурном уровне, например, в dependency injection framework. Ну или любой другой внешней конфигурации модулей и межмодульного взаимодействия. На шаблонах оно будет работать только до тех пор, пока известна информация о типах преобразуемых объектов.

Вообще, вся эта магия нужна, когда присутствуют сразу оба типа варианта, описаных Василием. Есть функция, тип результата которой зависит от значения. Такая функция возникает, когда есть какая-либо внешная конфигурация "верхнего" уровня, не выраженная в коде. И при этом есть функции, тип которых зависит от типа аргументов, вроде приведенных выше. В статическом случае их можно реализовать шаблонами/макросами и т.п. Но вот применить их к результату функций первого типа не получится без динамики .
Re[4]: Анонимные алгебраические типы. Более сложный случай.
От: FR  
Дата: 29.04.11 15:24
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Да, неплохо. Только вот мне не нравится, что это шаблон. Я хочу именно функцию. Чтобы ее можно было куда-нибудь еще передавать, например.


Этот шаблон порождает полноценную функцию полностью совпадающую по типу с ее функцией аргументом, с ней можно делать все что можно делать с любой другой функцией. Тут чуть разъясню, шаблоны D в отличии от шаблонов C++ могут порождать любые типы, а не только структуры/классы или функции.
Вот такой код:

writeln(typeid(typeof(TestInc)));
writeln(typeid(typeof(ExceptionProtect!(TestInc, TestExnHandler))));


выведет:

immutable(char)[]()
immutable(char)[]()


то есть типы совершенно одинаковы, от шаблона ничего ни осталось.

M>Я не против писать то, что в шаблоне написано, это позволит проверить типы там, где они известны на этапе компиляции. А там, где функция используется на динамике, пусть работает в "моем" варианте. Более того, пусть "статические" вызовы компилятор инлайнит, но динамика все равно остается. Потому что изначально метод предназначался для защиты функции, строящейся по конфигу во время исполнения, а не во время написания кода. Что-то вроде


В динамике конечно шаблоны бессильны.

.....

M>Более того, на основе этой же функции я могу, например, защищать "интерфейсы":


.....

M>Оно строит новый объект, имеющий те же поля (с теми же значениями) но функции обернуты и защищены.


А это на шаблонах вполне реально.

M>Полезно на инфраструктурном уровне, например, в dependency injection framework. Ну или любой другой внешней конфигурации модулей и межмодульного взаимодействия. На шаблонах оно будет работать только до тех пор, пока известна информация о типах преобразуемых объектов.


Конечно, но тут часто хватает обертки на базовый интерфейс.

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


Это да.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.