Re: Типы значений и коллекции
От: Пельмешко Россия blog
Дата: 19.09.10 14:17
Оценка: 1 (1) +1
Здравствуйте, darklight, Вы писали:

D>Здравствуйте. У меня есть нтерсеный вопрос.


D>Как бы реализовать коллекцию, которая смогла бы хранить значения разных типов, являющихся типами значений, в т.ч. и примитивными, без упаковки типов.


Если задача реально требует алгебраических типов, то можно попробовать взять соответствующий язык:
type Foo =
   | IntValue     of int
   | DoubleValue  of float
   | DecimalValue of decimal
 
let xs = [ IntValue 1; DoubleValue 1.23; DecimalValue 3.45M ]
 
List.iteri (printfn "%d: %A") xs

Или глянуть рефлектором в какие конструкции на C# превращается этот код
Re[16]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 20.09.10 00:06
Оценка: +1 :)
Здравствуйте, Sinix, Вы писали:

L>>Можно. Что-то типа.

S>Это вариант с кучей внутренних коллекций.

Это не суть важно. Главное, что можно.

S>Стоимость поиска вложенной коллекции убъёт всю выгоду от отсутствия боксинга.


Не зная кол-во типов, об этом сложно судить.

S>Очень сомневаюсь, в существовании контейнера для любых структур, что будет быстрее List<object>.


Не хотелось бы повторяться, но все-таки обсуждение подхода с боксингом — своего рода офтопик в данной теме. Топикстартер это дал явно понять. Разве нет?
Re[16]: Типы значений и коллекции
От: darklight  
Дата: 20.09.10 08:14
Оценка: 16 (1)
S>Сравните с производительностью Dictionary<string,object> (или обёртки вокруг неё)%)
Что я и сделал — см чуть выше результат ужасный!
Re[3]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 15:09
Оценка: 3 (1)
Здравствуйте, Lloyd, Вы писали:

L>Ну не обязательно же так топорно делать. Можно, например сделать, чтобы колеекция возвращала какой-нить IValueAccessor<T>, который будет генериться в рантайме.


Нда?
Core2Duo E8400, 4Gb RAM, Win7 x64.
Build target x86; RELEASE; запуск без дебаггера (по Ctrl-F5).

При заранее известном размере списка:
--------
                      List<int>:      59,0 ms;  mem:   39 070,5 Kb
                   List<object>:   1 235,0 ms;  mem:  156 250,4 Kb
                      ArrayList:   1 220,0 ms;  mem:  156 254,5 Kb
               ValueHolder<int>:   1 191,0 ms;  mem:  156 250,4 Kb
                 IntValueHolder:   1 193,0 ms;  mem:  156 250,4 Kb
 (IValueHolder)ValueHolder<int>:   1 437,0 ms;  mem:  156 250,4 Kb
   (IValueHolder)IntValueHolder:   1 416,0 ms;  mem:  156 250,4 Kb
--------
                      List<int>:      60,0 ms;  mem:   39 070,5 Kb
                   List<object>:   1 178,0 ms;  mem:  156 254,5 Kb
                      ArrayList:   1 197,0 ms;  mem:  156 254,5 Kb
               ValueHolder<int>:   1 176,0 ms;  mem:  156 250,5 Kb
                 IntValueHolder:   1 171,0 ms;  mem:  156 254,0 Kb
 (IValueHolder)ValueHolder<int>:   1 431,0 ms;  mem:  156 250,4 Kb
   (IValueHolder)IntValueHolder:   1 422,0 ms;  mem:  156 250,4 Kb
Done...


Динамический ресайз списка(просто замените "(count)" на "()"):
--------
                      List<int>:     135,0 ms;  mem:   98 304,1 Kb
                   List<object>:   1 567,0 ms;  mem:  215 496,0 Kb
                      ArrayList:   1 497,0 ms;  mem:  215 496,1 Kb
               ValueHolder<int>:   1 533,0 ms;  mem:  215 496,1 Kb
                 IntValueHolder:   1 441,0 ms;  mem:  215 496,1 Kb
 (IValueHolder)ValueHolder<int>:   1 622,0 ms;  mem:  215 492,1 Kb
   (IValueHolder)IntValueHolder:   1 628,0 ms;  mem:  215 492,0 Kb
--------
                      List<int>:     118,0 ms;  mem:   98 304,1 Kb
                   List<object>:   1 393,0 ms;  mem:  215 492,1 Kb
                      ArrayList:   1 406,0 ms;  mem:  215 492,1 Kb
               ValueHolder<int>:   1 401,0 ms;  mem:  215 492,1 Kb
                 IntValueHolder:   1 449,0 ms;  mem:  215 496,1 Kb
 (IValueHolder)ValueHolder<int>:   1 561,0 ms;  mem:  215 496,1 Kb
   (IValueHolder)IntValueHolder:   1 621,0 ms;  mem:  215 492,0 Kb
Done...

  код
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
  interface IValueHolder
  {
  }

  class ValueHolder<T> : IValueHolder
  {
    public T Value { get; private set; }
    public ValueHolder(T value)
    {
      Value = value;
    }
  }

  class IntValueHolder : IValueHolder
  {
    public int Value { get; private set; }
    public IntValueHolder(int value)
    {
      Value = value;
    }
  }

  class Program
  {
    const int count = 10 * 1000 * 1000;

    static void Main(string[] args)
    {
      Run();
      GC.Collect();
      GC.WaitForPendingFinalizers();
      GC.Collect();
      Run();

      Console.Write("Done...");
      Console.ReadKey();
    }

    private static void Run()
    {
      Console.WriteLine("--------");
      Measure("List<int>", () =>
      {
        var list = new List<int>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(i);
        }
      });

      Measure("List<object>", () =>
      {
        var list = new List<object>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(i);
        }
      });

      Measure("ArrayList", () =>
      {
        var list = new ArrayList(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(i);
        }
      });

      Measure("ValueHolder<int>", () =>
      {
        var list = new List<ValueHolder<int>>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new ValueHolder<int>(i));
        }
      });

      Measure("IntValueHolder", () =>
      {
        var list = new List<IntValueHolder>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new IntValueHolder(i));
        }
      });


      Measure("(IValueHolder)ValueHolder<int>", () =>
      {
        var list = new List<IValueHolder>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new ValueHolder<int>(i));
        }
      });

      Measure("(IValueHolder)IntValueHolder", () =>
      {
        var list = new List<IValueHolder>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new IntValueHolder(i));
        }
      });
    }

    static void Measure(string message, Action callback)
    {
      long mem = GC.GetTotalMemory(true);
      Stopwatch sw = Stopwatch.StartNew();
      callback();
      double elapsed = sw.ElapsedMilliseconds;
      long mem2 = GC.GetTotalMemory(false);
      Console.WriteLine(
        "{0,31}:{1,10:#,##0.0} ms;  mem: {2,10:#,##0.0} Kb",
        message,
        elapsed,
        (mem2 - mem) / 1024.0);
    }
  }
}


Кмк, больше обсуждать здесь нечего.
Re[8]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 15:48
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Если используем List<IValueAccessor> — эффекта практически незаметно (для малого количества объектов List<object>/ArrayList раза в полтора быстрее, но эта разница вполне может быть погрешностью измерения).


Ну вообще-то уже по самой формулировке вопроса List<object>/ArrayList рассматривать нельзя. Поэтому говорить о его скорости нет никакого смысла.
Re[2]: аналог boost::any?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.09.10 02:33
Оценка: :)
Здравствуйте, Константин Л., Вы писали:

КЛ>Что-то мне подсказывает, что f#/nemerle используют для алгебраических типов что-то подобное.

Что-то не право.
Re[9]: Типы значений и коллекции
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.09.10 14:44
Оценка: +1
Здравствуйте, darklight, Вы писали:
D>И использовать внутр только для хранения данных во внутренней коллекции. Как я уже говорил — снаружи будет отдельный посредник через которого можно получать и добавлять данные типизированным (через generic) образом — так что у клиента будет шанс использовать нужный метод с нужной типизацией получаемого/возвращаемого значения — а остальное уже не важно.
Вы, главное, поясните — зачем это? Чем вас так не устраивает боксинг?
Вы что, всерьёз полагаете, что затраты на анбоксинг при извлечении из коллекции настолько велики, что хранение вот этого вашего "супервариантного" типа будет ими оправдано?

Теперь такой вопрос: откуда ваш клиентский код знает, какого типа будет значение? Если он всегда достаёт из Limit int, то почему не сделать вместо "коллекции" нормальный класс с именованным полем?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: аналог boost::any?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.09.10 15:11
Оценка: -1
Здравствуйте, Константин Л., Вы писали:

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


S>>Популярный механизм реализации АТД на ООП (общий предок + наследование) был предложен на первой странице Пельмешком.


КЛ>на f#?

Да, и еще он предложил глянуть в рефлектор.
Re[7]: Типы значений и коллекции
От: Ocelot  
Дата: 23.09.10 23:47
Оценка: +1
Здравствуйте, Lloyd, Вы писали:


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


L>Гм. Такого требования вроде как не было.


"Добавление элементов с заменой значения, если таковой уже существует.
Получение значения по ключу.
Обновление значения по ключу."

То есть я так понимаю, в этом плане коллекция внешне должна быть похожа на IDictionary, при этом внутри делая "все красиво". Если реализация подразумевает использование нескольких приватных словарей (грубо говоря, отдельного на каждый тип), то должен же быть какой-то контроль за общей уникальностью?
Типы значений и коллекции
От: darklight  
Дата: 19.09.10 13:42
Оценка:
Здравствуйте. У меня есть нтерсеный вопрос.

Как бы реализовать коллекцию, которая смогла бы хранить значения разных типов, являющихся типами значений, в т.ч. и примитивными, без упаковки типов.

Использование generic-коллекций позволяет это хранить только типы значений одного типа, а вот как бы ъхранить значения разных типов значений без упаковки. Заранее типы значений для не известны, могут быть как структурами, так примитивными типами. И, хорошо было бы хранить также значение null (не прибегаю к упакованным nullable типам). Будем считать, что коллекция не требует упорядоченного индексирования.

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

Но вот, как бы ещё суметь вернуть значения разного типа из коллекции без боксинга?
Re: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 14:00
Оценка:
Здравствуйте, darklight, Вы писали:

D>Как бы реализовать коллекцию, которая смогла бы хранить значения разных типов, являющихся типами значений, в т.ч. и примитивными, без упаковки типов.

Никак. Можно сделать List<IValueHolder>, но:
1) если ValueHolder<T> — структура, она будет упакована сама.
2) если ValueHolder<T> — класс, то всё равно произойдёт копирование хранимой структуры в поле ValueHolder, т.е. в кучу.

Производительность в любом случае будет меньше, чем в варианте с List<object>.

D>Пока думаю, что нужно делать внутри коллекцию контейнеров-коллекций для каждого типа значений по отдельности и рапихивать добавляемые значения по этим коллекциям по ключу значения типа этих значений. А при перечислении (или посике) обходить эти коллекции а потоом вложенные коллекции-контнейрены.


Будет в разы медленнее.

Наконец, по сравнению с остальной частью приложения это будут такие копейки...
Если не секрет, чего вы хотите добиться?
Re[2]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 14:05
Оценка:
Здравствуйте, Sinix, Вы писали:

D>>Как бы реализовать коллекцию, которая смогла бы хранить значения разных типов, являющихся типами значений, в т.ч. и примитивными, без упаковки типов.

S>Никак. Можно сделать List<IValueHolder>, но:
S>1) если ValueHolder<T> — структура, она будет упакована сама.
S>2) если ValueHolder<T> — класс, то всё равно произойдёт копирование хранимой структуры в поле ValueHolder, т.е. в кучу.

Ну не обязательно же так топорно делать. Можно, например сделать, чтобы колеекция возвращала какой-нить IValueAccessor<T>, который будет генериться в рантайме.
Re: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 14:06
Оценка:
Здравствуйте, darklight, Вы писали:

D>Но вот, как бы ещё суметь вернуть значения разного типа из коллекции без боксинга?


Сначала определитесь с тем, какой api будет у вашей коллекции.
Re[2]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 15:12
Оценка:
Здравствуйте, Пельмешко, Вы писали:

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

П>Или глянуть рефлектором в какие конструкции на C# превращается этот код

По производительности будет то же самое, что и в моём посте выше. Проще не выделываться и взять List<object>.
Re[4]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 15:12
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Кмк, больше обсуждать здесь нечего.


Ты даже не понял о чем речь. При таком подходе обсуждать действительно нечего.
Re[5]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 15:23
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Ты даже не понял о чем речь. При таком подходе обсуждать действительно нечего.

Ок. Разъясните вашу точку зрения.

Сразу же вопрос: что даст динамическая генерация IValueAccessor<T>.
Re[6]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 15:26
Оценка:
Здравствуйте, Sinix, Вы писали:

L>>Ты даже не понял о чем речь. При таком подходе обсуждать действительно нечего.

S>Ок. Разъясните вашу точку зрения.

Подождем ответа на мой вопрос топикстартеру.

S>Сразу же вопрос: что даст динамическая генерация IValueAccessor<T>.


Возможность избавиться от боксинга.
Re[7]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 15:35
Оценка:
Здравствуйте, Lloyd, Вы писали:

S>>Сразу же вопрос: что даст динамическая генерация IValueAccessor<T>.

L>Возможность избавиться от боксинга.

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

Если используем List<IValueAccessor> — эффекта практически незаметно (для малого количества объектов List<object>/ArrayList раза в полтора быстрее, но эта разница вполне может быть погрешностью измерения).

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

Очевидно, вы имели в виду что-то другое.
Re[9]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 16:02
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Ну вообще-то уже по самой формулировке вопроса List<object>/ArrayList рассматривать нельзя. Поэтому говорить о его скорости нет никакого смысла.

Согласен. Только как можно добиться производительности, сопоставимой с List<T> — ума не приложу.
Re[10]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 16:13
Оценка:
Здравствуйте, Sinix, Вы писали:

L>>Ну вообще-то уже по самой формулировке вопроса List<object>/ArrayList рассматривать нельзя. Поэтому говорить о его скорости нет никакого смысла.

S>Согласен. Только как можно добиться производительности, сопоставимой с List<T> — ума не приложу.

Например, коллекция может возвращать типизированный "курсор" — аналог IEnumerable, который, зная о внутреннем устойстве коллекции будет уметь оптимально работать с элементами указанного типа.
Но, пока автор не прояснил, какие опреации он хочет видеть в своей коллекции, предлагать что-либо рано.
Re[11]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 16:24
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Например, коллекция может возвращать типизированный "курсор" — аналог IEnumerable, который, зная о внутреннем устойстве коллекции будет уметь оптимально работать с элементами указанного типа.


Для начала неплохо бы определиться с тем, как нам объекты в коллекцию засовывать так, чтобы вся эта возня вообще имела смысл.

Помимо варианта с несколькими коллекциями можно придумать страшно извращённый способ: завести массив байт и копировать в него структуры (например, ч/з unsafe или Marshal.Copy). Даже если этот кошмарик будет быстро работать, тут же возникает другая проблема — либо мы выравниваем значения (и кидаем исключение для больших структур), либо тратим время для нахождения смещения. Баш на баш.

L>Но, пока автор не прояснил, какие опреации он хочет видеть в своей коллекции, предлагать что-либо рано.

Да тут, по-моему, любой подход кроме использования List<object>(или обёртки вокруг него) бессмысленен.
Re[12]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 16:45
Оценка:
Здравствуйте, Sinix, Вы писали:

L>>Например, коллекция может возвращать типизированный "курсор" — аналог IEnumerable, который, зная о внутреннем устойстве коллекции будет уметь оптимально работать с элементами указанного типа.


S>Для начала неплохо бы определиться с тем, как нам объекты в коллекцию засовывать так, чтобы вся эта возня вообще имела смысл.


Вот и я о том же. Пока он не написал, каким он видит api его коллекции, предлагать что-либо бессмысленно
Re[12]: Типы значений и коллекции
От: darklight  
Дата: 19.09.10 17:24
Оценка:
Здравствуйте, Sinix, спасибо огромное за Ваш пример с замерами производиетльности. Я, честно говоря в шоке. Получает generic-версия List<T> всёравно приводит с боксингу при работе со структурами. Меня, крайне поразило сравнение List<int> и List<ValueHolder<int>> — разница огромна (List<ValueHolder<int>> по времени то же, что и List<object>). Хотя, не может ли это быть из-за затрат времени на создание самих структур.

Я, если честно, собирался использовать создание структур для "переупаковки" значений внутр контейнера и при работе с внешним "потребителем" (посредник между разными интерфейсами). Придётся, наверное отказаться от этого и завести две внутренних-коллекций контейнера — одна для самих значений Dictionary<string, T> — и хранить только значения одного типа, другая для хранения пометки, что значение по ключу заполнено (нужна такая потребность) — Dictionary<string, bool> или HashSet<string>. А для остальных случаев — использовать обычный Dictionary<string, object> (или просто Dictionary) и не обращать внимание на опирации боксинга (не так уж это и критично — вроде как не critical realtime процессы буду использовать эту коллекцию), а с приведением типов быть поосторожнее

Хотя, конечно, сравнивать с List<T> другие коллекции — это дело заранее проигрышное — ибо Lits<T> самая оптимизированная по производительности коллекция всего .NET фреймворка, на данный момент.
Re[13]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 17:31
Оценка:
Здравствуйте, darklight, Вы писали:

D>Хотя, конечно, сравнивать с List<T> другие коллекции — это дело заранее проигрышное — ибо Lits<T> самая оптимизированная по производительности коллекция всего .NET фреймворка, на данный момент.


Да ну? И что ж в ней такого оптимизированного?
Re[13]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 17:40
Оценка:
Здравствуйте, darklight, Вы писали:

D>Я, если честно, собирался использовать создание структур для "переупаковки" значений внутр контейнера и при работе с внешним "потребителем" (посредник между разными интерфейсами).

Пардон, у меня время позднее, попробую вдумчиво ответить завтра. А то щас намекнут, что я опять не понял вопроса

D>Хотя, конечно, сравнивать с List<T> другие коллекции — это дело заранее проигрышное — ибо Lits<T> самая оптимизированная по производительности коллекция всего .NET фреймворка, на данный момент.


Хохма не в том. ValueHolder'ы — это классы. Соответственно, расходы на их создание ничем не отличаются от боксинга int. Замените class IntValueHolder на struct
  код
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
  interface IValueHolder
  {
  }

  class ValueHolder<T> : IValueHolder
  {
    public T Value { get; private set; }
    public ValueHolder(T value)
    {
      Value = value;
    }
  }

  struct IntValueHolder : IValueHolder
  {
    public int Value { get; set; }
  }

  class Program
  {
    const int count = 10 * 1000 * 1000;

    static void Main(string[] args)
    {
      Run();
      GC.Collect();
      GC.WaitForPendingFinalizers();
      GC.Collect();
      Run();

      Console.Write("Done...");
      Console.ReadKey();
    }

    private static void Run()
    {
      Console.WriteLine("--------");
      Measure("List<int>", () =>
      {
        var list = new List<int>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(i);
        }
      });

      Measure("List<object>", () =>
      {
        var list = new List<object>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(i);
        }
      });

      Measure("ArrayList", () =>
      {
        var list = new ArrayList(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(i);
        }
      });

      Measure("ValueHolder<int>", () =>
      {
        var list = new List<ValueHolder<int>>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new ValueHolder<int>(i));
        }
      });

      Measure("IntValueHolder", () =>
      {
        var list = new List<IntValueHolder>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new IntValueHolder() { Value = i});
        }
      });


      Measure("(IValueHolder)ValueHolder<int>", () =>
      {
        var list = new List<IValueHolder>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new ValueHolder<int>(i));
        }
      });

      Measure("(IValueHolder)IntValueHolder", () =>
      {
        var list = new List<IValueHolder>(count);
        for (int i = 0; i < count; i++)
        {
          list.Add(new IntValueHolder {Value = i });
        }
      });
    }
    static void Measure(string message, Action callback)
    {
      long mem = GC.GetTotalMemory(true);
      Stopwatch sw = Stopwatch.StartNew();
      callback();
      double elapsed = sw.ElapsedMilliseconds;
      long mem2 = GC.GetTotalMemory(false);
      Console.WriteLine(
        "{0,31}:{1,10:#,##0.0} ms;  mem: {2,10:#,##0.0} Kb",
        message,
        elapsed,
        (mem2 - mem) / 1024.0);
    }
  }
}

и вы получите поведение аналогичное List<int>
--------
                      List<int>:      62,0 ms;  mem:   39 070,5 Kb
                   List<object>:   1 397,0 ms;  mem:  156 254,4 Kb
                      ArrayList:   1 254,0 ms;  mem:  156 254,5 Kb
               ValueHolder<int>:   1 195,0 ms;  mem:  156 250,4 Kb
                 IntValueHolder:      60,0 ms;  mem:   39 070,5 Kb
 (IValueHolder)ValueHolder<int>:   1 465,0 ms;  mem:  156 257,5 Kb
   (IValueHolder)IntValueHolder:   1 498,0 ms;  mem:  156 253,7 Kb
--------
                      List<int>:      70,0 ms;  mem:   39 070,5 Kb
                   List<object>:   1 227,0 ms;  mem:  156 250,5 Kb
                      ArrayList:   1 244,0 ms;  mem:  156 254,5 Kb
               ValueHolder<int>:   1 220,0 ms;  mem:  156 254,5 Kb
                 IntValueHolder:      59,0 ms;  mem:   39 070,5 Kb
 (IValueHolder)ValueHolder<int>:   1 474,0 ms;  mem:  156 250,4 Kb
   (IValueHolder)IntValueHolder:   1 473,0 ms;  mem:  156 250,4 Kb
Done...


Только это ничего не даст — универсальный контейнер для value-типов без боксинга создать нельзя.
Re[2]: Типы значений и коллекции
От: darklight  
Дата: 19.09.10 17:43
Оценка:
API моей коллекции:
Хранение значений — как ссылочных, так и типов-значения (в т.ч. примитивных), а так же специального значения: Undefined — когда оно не заполнено (и все null ссылки автоматически приравниваются-преобразуются в это значение при добавлении).
Доступ к значению по ключу (строковому, но будет версия и с произвольным).
Добавление элементов с заменой значения, если таковой уже существует.
Получение значения по ключу.
Обновление значения по ключу.
Перебор коллекции с возвращение связной пары в виде структуры (ключ, значение, флаг, что значение было заполнено).
Удаление и очистка — есть, но практически не будет востребовано, больше будет востребовано быстрое создание и заполнение "фиксированным" набором значений, а так же их последующее обновление. Поиск и получение значения — так же должен быть очень быстрым.

К коллекция будет использована как основа для других коллекций — разного назначения: как маленьких (по количеству элементов) — требующих разового заполнения и разового использования, так и больших — требующих быстрого поиска и добавления/обновления. Будет версия и для dinamic-использования с прямым доступом через динамические поля к значениям, будет версия static-использования с привязкой фиксированного интерфейса в качестве аксесора к значениям коллекции через свойства интерфейса.

А вообще-то здесь больше востребована реализация промежуточного слоя для отделения коллекции-контейнера от потребителя отдельным ограниченным-интерфейсом (с определёнными наименованиями членов), хранение незаполненных значений по ключу (одного вида — для удобства сравнения, независимо для ссылочных и типов-значений объектов), а так же размещать внутри коллекции разные версии коллекций-конйтенеров (например sequantial и parallel, local и remote, array и database-access).

В общем, я видимо "забью" на боксинг и буд использовать Dictionary<string, object> для контейнера значений коллекции (+ отдельная версия Dictionary<string, T> для работы со значениями одного типа — ибо таких будет много; а первый вариант так же не проиграет в производительности и при значениях разного ссылочный-типа, только с привидением типов нужно будет быть поаккуратнее).

Но, в общем-то, generic версия List<T> при работе со структурами меня очень разочаровала — вот тебе и generic-преимущества при построении коллекций с типами-значениями не примитивных типов).
Re[14]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 17:44
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Только это ничего не даст — универсальный контейнер для value-типов без боксинга создать нельзя.


Можно. Что-то типа
coll.GetAccessor<int>().Add(123);

, где Accessor будет генериться в динамике.
Re[14]: Типы значений и коллекции
От: darklight  
Дата: 19.09.10 17:46
Оценка:
Здравствуйте, Lloyd, Вы писали:
L>Да ну? И что ж в ней такого оптимизированного?
Просто я читал про это в интернете и в какой-то книге Сам не углублялся пока ещё в этот вопрос
Re[14]: Типы значений и коллекции
От: darklight  
Дата: 19.09.10 18:18
Оценка:
Здравствуйте, Sinix, Вы писали:

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


D>>Я, если честно, собирался использовать создание структур для "переупаковки" значений внутр контейнера и при работе с внешним "потребителем" (посредник между разными интерфейсами).

S>Пардон, у меня время позднее, попробую вдумчиво ответить завтра. А то щас намекнут, что я опять не понял вопроса

S>Хохма не в том. ValueHolder'ы — это классы. Соответственно, расходы на их создание ничем не отличаются от боксинга int. Замените class

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

class myContainer
    {
        Dictionary<Type, System.Collections.IDictionary> OuterCollection;
        public void Add<T>(string key, T value)
        {
            var valueType = typeof (T);
            System.Collections.IDictionary newInnerCollection;
            if (!OuterCollection.ContainsKey(valueType))
            {
                newInnerCollection = new Dictionary<string, T>();
                OuterCollection.Add(valueType,newInnerCollection);
            }
            else
            {
                newInnerCollection = OuterCollection[valueType];
            }
            Dictionary<string, T> innerCollection = (Dictionary<string, T>)newInnerCollection;
            innerCollection.Add(key, value);
        }
            
        public T GetValue<T>(string key, out bool contains)
        {
            var valueType = typeof (T);
            if (!OuterCollection.ContainsKey(valueType))
            {
                contains = false;
                return default(T);
            }
            
            System.Collections.IDictionary _InnerCollection = OuterCollection[valueType];
            Dictionary<string, T> innerCollection = (Dictionary<string, T>)_InnerCollection;
            contains = innerCollection.ContainsKey(key);
            if (!contains)
                return default(T);

            var value = innerCollection[key];
            return value;
        }

        public void SetValue<T>(string key, T value)
        {
            var valueType = typeof (T);
            System.Collections.IDictionary newInnerCollection;
            if (!OuterCollection.ContainsKey(valueType))
            {
                newInnerCollection = new Dictionary<string, T>();
                OuterCollection.Add(valueType,newInnerCollection);
            }
            else
            {
                newInnerCollection = OuterCollection[valueType];
            }
            Dictionary<string, T> innerCollection = (Dictionary<string, T>)newInnerCollection;
            bool contains = innerCollection.ContainsKey(key);
            if (!contains)
                innerCollection.Add(key, value);
            else
                innerCollection[key] = value;
        }
    }


как-то так
Re: Типы значений и коллекции
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.09.10 19:38
Оценка:
Здравствуйте, darklight, Вы писали:

D>Здравствуйте. У меня есть нтерсеный вопрос.


D>Как бы реализовать коллекцию, которая смогла бы хранить значения разных типов, являющихся типами значений, в т.ч. и примитивными, без упаковки типов.


D>Использование generic-коллекций позволяет это хранить только типы значений одного типа, а вот как бы ъхранить значения разных типов значений без упаковки. Заранее типы значений для не известны, могут быть как структурами, так примитивными типами. И, хорошо было бы хранить также значение null (не прибегаю к упакованным nullable типам). Будем считать, что коллекция не требует упорядоченного индексирования.


D>Пока думаю, что нужно делать внутри коллекцию контейнеров-коллекций для каждого типа значений по отдельности и рапихивать добавляемые значения по этим коллекциям по ключу значения типа этих значений. А при перечислении (или посике) обходить эти коллекции а потоом вложенные коллекции-контнейрены.


D>Но вот, как бы ещё суметь вернуть значения разного типа из коллекции без боксинга?


А какова цель всего этого действа?

Приведи пример как оно будет использоваться.

Странно что этот вопрос еще никто не задал.
Re[15]: Типы значений и коллекции
От: darklight  
Дата: 19.09.10 19:41
Оценка:
Пробовал протестировать свой вариант коллекции в тесте от Sinix — о ужас — затраты даже выше чем с боксингом Lits<object> (но ниже чем Dictionary<int, object>, но у полной реализации (myContainer) уже выше)
Но — удивляет что даже такой класс

class myContainer2<K>
    {
        Dictionary<Type, Dictionary<K, int>> OuterCollection = new Dictionary<Type, Dictionary<K, int>>(1000);

        public myContainer2(int capacity)
        {
            OuterCollection.Add(typeof(int), new Dictionary<K, int>(capacity));
        }

        public void Add(K key, int value)
        {
            var innerCollection = OuterCollection[typeof(int)];
            innerCollection.Add(key, value);
        }      
    }


имеет следующую разницу в сравнении с обычным Dictionary<int,ValueHolder<int>>
--------
--------
Dictionary<int, object>: 3 415,0 ms; mem: 312 504,2 Kb
Dictionary<int, ValueHolder<int>>: 710,0 ms; mem: 195 313,0 Kb
myContainer: 4 173,0 ms; mem: 195 334,6 Kb
myContainer2: 2 727,0 ms; mem: 195 334,6 Kb
--------
Dictionary<int, object>: 3 221,0 ms; mem: 312 506,2 Kb
Dictionary<int, ValueHolder<int>>: 700,0 ms; mem: 195 313,0 Kb
myContainer: 4 302,0 ms; mem: 195 334,6 Kb
myContainer2: 2 811,0 ms; mem: 195 334,6 Kb
Done...


при следующем коде теста:

            Measure("Dictionary<int, object>", () =>
            {
                var list = new Dictionary<int, object>(count);
                for (int i = 0; i < count; i++)
                {
                    list.Add(i, i);
                }
            });

            Measure("Dictionary<int, ValueHolder<int>>", () =>
            {
                var list = new Dictionary<int, ValueHolder<int>>(count);
                for (int i = 0; i < count; i++)
                {
                    list.Add(i, new ValueHolder<int>() { Value = i });
                }
            });

            Measure("myContainer", () =>
            {
                var list = new myContainer<int>(count);
                for (int i = 0; i < count; i++)
                {
                    //list.Add<ValueHolder<int>>(i, new ValueHolder<int>() { Value = i });
                    list.Add(i, i);
                }
            });

            Measure("myContainer2", () =>
            {
                var list = new myContainer2<int>(count);
                for (int i = 0; i < count; i++)
                {
                    //list.Add<ValueHolder<int>>(i, new ValueHolder<int>() { Value = i });
                    list.Add(i, i);
                }
            });


Прямо-таки я остался очень озадачен данным результатом. Видимо придётся оставить реализацию с боксингом на Dictionary<string, object> — как наиболее простую и даже более производительную чем иные решения, которые могу прийти мне в голову.

код полного myContainer в последней версии:

class myContainer<K>
    {
        Dictionary<Type, System.Collections.IDictionary> OuterCollection = new Dictionary<Type, System.Collections.IDictionary>(1000);
        private int capacity;
        public myContainer(int capacity)
        {
            this.capacity = capacity;  
        }



        public void Add<T>(K key, T value)
        {
            var valueType = typeof(T);
            System.Collections.IDictionary newInnerCollection;
            if (!OuterCollection.ContainsKey(valueType))
            {
                newInnerCollection = new Dictionary<K, T>(capacity);
                OuterCollection.Add(valueType, newInnerCollection);
            }
            else
            {
                newInnerCollection = OuterCollection[valueType];
            }
            Dictionary<K, T> innerCollection = (Dictionary<K, T>)newInnerCollection;
            innerCollection.Add(key, value);
        }

        public T GetValue<T>(K key, out bool contains)
        {
            var valueType = typeof(T);
            if (!OuterCollection.ContainsKey(valueType))
            {
                contains = false;
                return default(T);
            }

            System.Collections.IDictionary _InnerCollection = OuterCollection[valueType];
            Dictionary<K, T> innerCollection = (Dictionary<K, T>)_InnerCollection;
            contains = innerCollection.ContainsKey(key);
            if (!contains)
                return default(T);

            var value = innerCollection[key];
            return value;
        }

        public void SetValue<T>(K key, T value)
        {
            var valueType = typeof(T);
            System.Collections.IDictionary newInnerCollection;
            if (!OuterCollection.ContainsKey(valueType))
            {
                newInnerCollection = new Dictionary<K, T>();
                OuterCollection.Add(valueType, newInnerCollection);
            }
            else
            {
                newInnerCollection = OuterCollection[valueType];
            }
            Dictionary<K, T> innerCollection = (Dictionary<K, T>)newInnerCollection;
            bool contains = innerCollection.ContainsKey(key);
            if (!contains)
                innerCollection.Add(key, value);
            else
                innerCollection[key] = value;
        }
    }
Re[2]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 19.09.10 19:41
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Странно что этот вопрос еще никто не задал.


Странно, что ты не прчитал тред, прежде чем писать.
Re[2]: Типы значений и коллекции
От: darklight  
Дата: 19.09.10 19:42
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>А какова цель всего этого действа?


вроде уже написал — смотри выше!
Re[3]: Типы значений и коллекции
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.09.10 19:48
Оценка:
Здравствуйте, darklight, Вы писали:

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


G>>А какова цель всего этого действа?


D>вроде уже написал — смотри выше!


Не, расскажи что будет делать клиентский код.

Ведь даже если добьешься каким-то чудом отсутствия боксинга в коллекции, то клиентский код будет использовать обычные generic_и или тот же боксинг value-типов.

Дополнительный уровень косвенности, который ты внесешь, все равно ниче не даст.

ЗЫ. Кстати для mutable и immutable коллекций используются разные структуры данных.
Re[4]: Типы значений и коллекции
От: darklight  
Дата: 19.09.10 21:01
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Не, расскажи что будет делать клиентский код.
былоздесь
Автор: darklight
Дата: 19.09.10

и здесь
Автор: darklight
Дата: 19.09.10

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

G>Ведь даже если добьешься каким-то чудом отсутствия боксинга в коллекции, то клиентский код будет использовать обычные generic_и или тот же боксинг value-типов.

G>ЗЫ. Кстати для mutable и immutable коллекций используются разные структуры данных.
Не совсем понял, что тут и тут имелось ввиду.
Поидеи клиенкский код в основном будет либо передавать значения констант (прописанных в коде в месте примения) дибо ссылочные объекты, либо получать и передавать значения из типизированных источников.
Re[15]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 23:55
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Можно. Что-то типа.

Это вариант с кучей внутренних коллекций. Стоимость поиска вложенной коллекции убъёт всю выгоду от отсутствия боксинга.

Очень сомневаюсь, в существовании контейнера для любых структур, что будет быстрее List<object>.
Re[15]: Типы значений и коллекции
От: Sinix  
Дата: 19.09.10 23:58
Оценка:
Здравствуйте, darklight, Вы писали:

D>как-то так

Сравните с производительностью Dictionary<string,object> (или обёртки вокруг неё)%)
Re[5]: Типы значений и коллекции
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 20.09.10 05:30
Оценка:
Здравствуйте, darklight, Вы писали:

G>>Ведь даже если добьешься каким-то чудом отсутствия боксинга в коллекции, то клиентский код будет использовать обычные generic_и или тот же боксинг value-типов.

G>>ЗЫ. Кстати для mutable и immutable коллекций используются разные структуры данных.
D>Не совсем понял, что тут и тут имелось ввиду.
D>Поидеи клиенкский код в основном будет либо передавать значения констант (прописанных в коде в месте примения) дибо ссылочные объекты, либо получать и передавать значения из типизированных источников.


Ну тогда клиентский код будет пользоваться Generic_ами или боксингом в object, иначе неюзабельно получится. И получатся теже результаты тестов независимо от того что используется внутри коллекций.
Re[6]: Типы значений и коллекции
От: darklight  
Дата: 20.09.10 08:55
Оценка:
G>Ну тогда клиентский код будет пользоваться Generic_ами или боксингом в object, иначе неюзабельно получится. И получатся теже результаты тестов независимо от того что используется внутри коллекций.
Вот, я и говорю, что, видимо придётся оставить две версии: одну — generic — для работы со значениями строго одного типа — и одну с боксингом в object — для работы с любыми ссылочными типами и остальных смешанных случаев — когда допустимы элементы разных типов значений или в смеси с ссылочными типами. Хотя можно ещё предусмотреть один вариант (правда неэффектвиный с точки зрения расхода памяти, но это не очень принципиально): когда буду использоваться встроенные структруы-контейнеры для хранения значений основных типов-значений как одноц елоем — как-то вот так:

struct ValueContainer<TMyValue1, TMyValue2, TMyValue3, TMyValue4>
{
   public enum TypeOfValue {ValueObject, ValueInt, ValueDecimal, ValueBool, Value1, Value2, Value3, Value4}

   public object ValueObject; //For all ref objects

   public int ValueInt;
   public Decimal ValueDecimal;
   public bool ValueBool;

   //For user's struct valuetype
   public TMyValue1 Value1;
   public TMyValue2 Value2;
   public TMyValue3 Value3;
   public TMyValue4 Value4;

   public TypeOfValue TypeValue;

   public T GetValue<T>()
   {
     var t = typeof(T);
     if ((t==typeof(int)) && (TypeValue==TypeOfValue.ValueInt))
       return (T)ValueInt;
     else if ((t==typeof(decimal)) && (TypeValue==TypeOfValue.ValueDecimal))
       return (T)ValueDecimal;

     //etc

     else if ((t!=typeof(ValueType)) && (TypeValue==TypeOfValue.ValueObject))
       return (T)ValueObject;
     else
       throw InvaliOperationException();

   }

   //public void SetValue(int value)
   //public void SetValue(decimal value)

   //etc

   //public void SetValue(object value)
   public void SetValue<T>(T value)
   {
     var t = typeof(T);
     if (t==typeof(int))
     {
       ValueInt = (int)value;
       TypeValue = TypeOfValue.ValueInt;
     }
     else if (t==typeof(decimal))
     {
       ValueDecimal = (decimal)value;
       TypeValue = TypeOfValue.ValueDecimal;
     }

     //etc

     else if (t==typeof(TValue4))
     {
       Value4 = (TValue4)value;
       TypeValue = TypeOfValue.Value4;
     }
     else
     {
       ValueObject = (object)value;
       TypeValue = TypeOfValue.ValueObject;
     }
   }

}


Ну — ещё сюда бы добавить автоматическое приведение типов от меньшего к большему (float, double to decimal, заменить int на long и приводить int to long), аналогично преобразовывать при получении значения назад с созданием ошибки при преобразовании реально большего числа к меньшему.
Типы TValue1...TValue4 — предназначены для пользовательских структур — думаю, 4-х вариаций будет достаточно
Да, конечно, такой контейнер далёк от оптимальности по выделению памяти под большие коллекции — зато не будет боксинга в большинстве случаев. А для постых случаев — будут коллекции по одному generic-типу и с использованием object-контейнера.
Можно так же реализовать версию без пользовательских типов TValue1...TValue4, а так же для экстремального случая только с пользовательскими типами, но уже, скажем с 16-ью: TValue1...TValue16 + object-поле (примитивные типы могут быть размещены в одном из TValueN в случае необходимости) — итого будет 5 версий контейнера.
Re[7]: Типы значений и коллекции
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 20.09.10 09:03
Оценка:
Здравствуйте, darklight, Вы писали:

D>Да, конечно, такой контейнер далёк от оптимальности по выделению памяти под большие коллекции — зато не будет боксинга в большинстве случаев. А для постых случаев — будут коллекции по одному generic-типу и с использованием object-контейнера.

Боксинг все равно будет в клиентском коде, если он не знает с каким типом работает, то все равно будет получать object где-то на входе. Ведь вы не сможете везде использовать вашу структуру ValueContainer, как минимум FCL о ней не знает.

Вот поэтому я и говорю что нет смысла добиваться отсутствия боксинга всякими хаками, лучше использовать generic_и или нетипизированные коллекции.
Re[8]: Типы значений и коллекции
От: darklight  
Дата: 20.09.10 09:21
Оценка:
Здравствуйте, gandjustas, Вы писали:

D>>Да, конечно, такой контейнер далёк от оптимальности по выделению памяти под большие коллекции — зато не будет боксинга в большинстве случаев. А для постых случаев — будут коллекции по одному generic-типу и с использованием object-контейнера.

G>Боксинг все равно будет в клиентском коде, если он не знает с каким типом работает, то все равно будет получать object где-то на входе. Ведь вы не сможете везде использовать вашу структуру ValueContainer, как минимум FCL о ней не знает.
Я её хочу использовать только внутри коллекции и не выдавать доступа к ней пользователю (ну только через отдельные методы — если пользователь точно знает с чем работает, например для передачи значения между несколькими коллекциями, поддерживающими такой подход, а весь API приложения будет поддерживать такой подход при работе с коллекциями и одиночными значениями).
И использовать внутр только для хранения данных во внутренней коллекции. Как я уже говорил — снаружи будет отдельный посредник через которого можно получать и добавлять данные типизированным (через generic) образом — так что у клиента будет шанс использовать нужный метод с нужной типизацией получаемого/возвращаемого значения — а остальное уже не важно.
Re[3]: Типы значений и коллекции
От: Ocelot  
Дата: 22.09.10 21:12
Оценка:
Здравствуйте, darklight, Вы писали:

D>API моей коллекции:

D>Хранение значений — как ссылочных, так и типов-значения (в т.ч. примитивных), а так же специального значения: Undefined — когда оно не заполнено (и все null ссылки автоматически приравниваются-преобразуются в это значение при добавлении).
D>Доступ к значению по ключу (строковому, но будет версия и с произвольным).

И какая сигнатура будет у этого метода?

public ? get(String key) — вот что вместо вопросика планируется?

Думаю, как ни крути, придется методу возвращать object — но тогда, как бы вы ни хранили структуры внутри, даже и без упаковки, вот тут-то и получится боксинг.

А если сделать типизированные методы типа getInt16, getIn32 и т.п. — произвольные структуры хранить не получится.

Что-то не выходит цветок-то каменный.
Re[3]: Типы значений и коллекции
От: Аноним  
Дата: 22.09.10 21:35
Оценка:
Здравствуйте, Sinix, Вы писали:

S>По производительности будет то же самое, что и в моём посте выше. Проще не выделываться и взять List<object>.

лучше List<ValueType>
Re[4]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 22.09.10 21:57
Оценка:
Здравствуйте, Ocelot, Вы писали:

O>И какая сигнатура будет у этого метода?


O>public ? get(String key) — вот что вместо вопросика планируется?


public T get<T>(String key)?

O>Думаю, как ни крути, придется методу возвращать object — но тогда, как бы вы ни хранили структуры внутри, даже и без упаковки, вот тут-то и получится боксинг.


O>А если сделать типизированные методы типа getInt16, getIn32 и т.п. — произвольные структуры хранить не получится.


Почему не получится-то? Внутри generic-метода get ищем словарь нужного типа (IDictionary<string, T>) и из него вытягиваем значение. Где в этом сценарии боксинг будет?
Re: аналог boost::any?
От: Константин Л. Франция  
Дата: 23.09.10 00:31
Оценка:
Здравствуйте, darklight, Вы писали:

Если число типов невелико, скажем, 2-4, я бы может быть сделал так:


public sealed class Any<T1, T2, T3>
    {
        public bool HasValue1 { get; private set; }
        public T1 Value1 { get; private set; }

        public bool HasValue2 { get; private set; }
        public T2 Value2 { get; private set; }

        public bool HasValue3 { get; private set; }
        public T3 Value3 { get; private set; }

        public Any(T1 t1)
        {
            Value1 = t1;
            HasValue1 = true;
        }

        public Any(T2 t2)
        {
            Value2 = t2;
            HasValue2 = true;
        }

        public Any(T3 t3)
        {
            Value3 = t3;
            HasValue3 = true;
        }
    }

   
    public class Void {}


красивым это не назовешь, но если сильно хочется...

Что-то мне подсказывает, что f#/nemerle используют для алгебраических типов что-то подобное.
Re[2]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 23.09.10 08:20
Оценка:
Здравствуйте, Пельмешко, Вы писали:

D>>Как бы реализовать коллекцию, которая смогла бы хранить значения разных типов, являющихся типами значений, в т.ч. и примитивными, без упаковки типов.


П>Или глянуть рефлектором в какие конструкции на C# превращается этот код


Сам-то глянул? Как там с боксингом?
Re[3]: аналог boost::any?
От: Константин Л. Франция  
Дата: 23.09.10 13:36
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:


КЛ>>Что-то мне подсказывает, что f#/nemerle используют для алгебраических типов что-то подобное.

S>Что-то не право.

nemerle точно, только там механизм немного другой, а идея та же
Re[4]: аналог boost::any?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.09.10 14:35
Оценка:
Здравствуйте, Константин Л., Вы писали:

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


S>>Здравствуйте, Константин Л., Вы писали:


КЛ>>>Что-то мне подсказывает, что f#/nemerle используют для алгебраических типов что-то подобное.

S>>Что-то не право.

КЛ>nemerle точно, только там механизм немного другой, а идея та же


http://www.rsdn.ru/article/nemerle/Amplifier.xml#E62AE
Автор(ы): Чистяков Влад (VladD2)
Дата: 03.03.2007
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой мак-росов. Однако и без них Nemerle предоставляет ряд су-щественных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного програм-мирования, поддерживает функциональное программи-рование. Это выражается в наличии конструкций, упро-щающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонс-трировать это.

В зависимости от точки зрения варианты можно трактовать как ограниченный набор sealed-классов, имеющий общего предка, как эдакий типобезопасный аналог конструкции union из языка C, или как умную «штуковину», именуемую алгебраическими типами данных.

Сильно сомневаюсь, что реализация в немерле существенно отличается от данной трактовке и близка к объединению всех полей под все конструкторы в одной сущности. Хотя, не очень ясно, что значит "механизм немного другой"...
Re[5]: аналог boost::any?
От: Константин Л. Франция  
Дата: 23.09.10 14:53
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:


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


S>>>Здравствуйте, Константин Л., Вы писали:


КЛ>>>>Что-то мне подсказывает, что f#/nemerle используют для алгебраических типов что-то подобное.

S>>>Что-то не право.

КЛ>>nemerle точно, только там механизм немного другой, а идея та же


S>http://www.rsdn.ru/article/nemerle/Amplifier.xml#E62AE
Автор(ы): Чистяков Влад (VladD2)
Дата: 03.03.2007
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой мак-росов. Однако и без них Nemerle предоставляет ряд су-щественных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного програм-мирования, поддерживает функциональное программи-рование. Это выражается в наличии конструкций, упро-щающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонс-трировать это.

S>

S>В зависимости от точки зрения варианты можно трактовать как ограниченный набор sealed-классов, имеющий общего предка, как эдакий типобезопасный аналог конструкции union из языка C, или как умную «штуковину», именуемую алгебраическими типами данных.


S>Сильно сомневаюсь, что реализация в немерле существенно отличается от данной трактовке и близка к объединению всех полей под все конструкторы в одной сущности. Хотя, не очень ясно, что значит "механизм немного другой"...


не отличается, рефлектор это подтверждает, а вот общий предок и наследование/один типа как у меня — это и есть механизм.
Re[6]: аналог boost::any?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.09.10 15:00
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>не отличается, рефлектор это подтверждает, а вот общий предок и наследование/один типа как у меня — это и есть механизм.


А я уж было испугался за Nemerle
Популярный механизм реализации АТД на ООП (общий предок + наследование) был предложен на первой странице Пельмешком.
Re[7]: аналог boost::any?
От: Константин Л. Франция  
Дата: 23.09.10 15:03
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:


КЛ>>не отличается, рефлектор это подтверждает, а вот общий предок и наследование/один типа как у меня — это и есть механизм.


S>А я уж было испугался за Nemerle

S>Популярный механизм реализации АТД на ООП (общий предок + наследование) был предложен на первой странице Пельмешком.

на f#?
Re[7]: аналог boost::any?
От: Константин Л. Франция  
Дата: 23.09.10 15:13
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:


КЛ>>не отличается, рефлектор это подтверждает, а вот общий предок и наследование/один типа как у меня — это и есть механизм.


S>А я уж было испугался за Nemerle

S>Популярный механизм реализации АТД на ООП (общий предок + наследование) был предложен на первой странице Пельмешком.

более того, прозрачно и удобно АТД без языковой поддержки можно сделать только с пом. насл., но там проверка типа + апкаст.

на чем ты меня хочешь поймать? идея одна и та же, только в f#/n наследование, а у меня "композиция".
Re[9]: аналог boost::any?
От: Константин Л. Франция  
Дата: 23.09.10 15:14
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:


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


S>>>Популярный механизм реализации АТД на ООП (общий предок + наследование) был предложен на первой странице Пельмешком.


КЛ>>на f#?

S>Да, и еще он предложил глянуть в рефлектор.

ты тут самоутверждаешься? как заимплеменчены variant's в nemerle я знаю и без тебя и не первый год.
Re[10]: аналог boost::any?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.09.10 15:21
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>>>на f#?

S>>Да, и еще он предложил глянуть в рефлектор.

КЛ>ты тут самоутверждаешься? как заимплеменчены variant's в nemerle я знаю и без тебя и не первый год.


Нет, не самоутверждаюсь. Хотел внести ясность по поводу "подобности" механизмов наследования и композиции. Если ты и вправду хочешь считать их подобными, не буду мешать.
Re[11]: аналог boost::any?
От: Константин Л. Франция  
Дата: 23.09.10 15:26
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:


КЛ>>>>на f#?

S>>>Да, и еще он предложил глянуть в рефлектор.

КЛ>>ты тут самоутверждаешься? как заимплеменчены variant's в nemerle я знаю и без тебя и не первый год.


S>Нет, не самоутверждаюсь. Хотел внести ясность по поводу "подобности" механизмов наследования и композиции. Если ты и вправду хочешь считать их подобными, не буду мешать.


с точки зрения достижения конечной цели — да. а лекций по ооп и тп мне не нужно, спасибо
Re[5]: Типы значений и коллекции
От: Ocelot  
Дата: 23.09.10 20:24
Оценка:
Здравствуйте, Lloyd, Вы писали:

O>>Думаю, как ни крути, придется методу возвращать object — но тогда, как бы вы ни хранили структуры внутри, даже и без упаковки, вот тут-то и получится боксинг.


L>Почему не получится-то? Внутри generic-метода get ищем словарь нужного типа (IDictionary<string, T>) и из него вытягиваем значение. Где в этом сценарии боксинг будет?


Да, согласен, погорячился.
Но оверхед будет еще тот — во-первых, сперва найти/добавить нужную типизированную коллекцию.
Во-вторых, перебирать все коллекции при добавлении/изменении значения по ключу (ну или еще каким-то способом организовать проверку общей уникальности ключа).
Сомневаюсь, что будет быстрее нетипизированного варианта с боксингом.
Re[6]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 23.09.10 20:33
Оценка:
Здравствуйте, Ocelot, Вы писали:

O>Но оверхед будет еще тот — во-первых, сперва найти/добавить нужную типизированную коллекцию.


И где тут "еще тот"? Достаточно организавать словарь словарей. Вроде не должно быть особого оверхеда.

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


Гм. Такого требования вроде как не было.
Re[5]: Типы значений и коллекции
От: Ocelot  
Дата: 23.09.10 23:58
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>public T get<T>(String key)?


O>>Думаю, как ни крути, придется методу возвращать object — но тогда, как бы вы ни хранили структуры внутри, даже и без упаковки, вот тут-то и получится боксинг.


L>Почему не получится-то? Внутри generic-метода get ищем словарь нужного типа (IDictionary<string, T>) и из него вытягиваем значение. Где в этом сценарии боксинг будет?


Да, и кстати, это все будет работать только если T заранее известно.
Типа string val = collection.get("key") — вызовется get<string>.
А как быть, если как раз и не известно, какого типа значение хранится по этому ключу (если вообще хранится)?
Доступ к значению по ключу автор упоминает, а вот запрос, какой тип имеет значение (естественно, без непосредственного запроса самого значения) явно упущен.

Мне кажется, в самой концепции таки есть противоречие, мало совместимое с жизнью.
Re[6]: Типы значений и коллекции
От: Ocelot  
Дата: 24.09.10 00:13
Оценка:
Здравствуйте, Ocelot, Вы писали:

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


L>>public T get<T>(String key)?


O>>>Думаю, как ни крути, придется методу возвращать object — но тогда, как бы вы ни хранили структуры внутри, даже и без упаковки, вот тут-то и получится боксинг.


L>>Почему не получится-то? Внутри generic-метода get ищем словарь нужного типа (IDictionary<string, T>) и из него вытягиваем значение. Где в этом сценарии боксинг будет?


O>Да, и кстати, это все будет работать только если T заранее известно.


А вот пусть даже и известно, кстати.

MyClass mc = collection.get("myclass");
mc.Property = newValue;
MyStruct ms = collection.get("mystruct");
ms.Property = newValue;


Надеюсь, идея ясна?
Как-то не очень горю желанием нарваться на такую коллекцию.
Re[6]: Типы значений и коллекции
От: Lloyd Россия  
Дата: 24.09.10 07:27
Оценка:
Здравствуйте, Ocelot, Вы писали:

L>>Почему не получится-то? Внутри generic-метода get ищем словарь нужного типа (IDictionary<string, T>) и из него вытягиваем значение. Где в этом сценарии боксинг будет?


O>Да, и кстати, это все будет работать только если T заранее известно.

O>Типа string val = collection.get("key") — вызовется get<string>.
O>А как быть, если как раз и не известно, какого типа значение хранится по этому ключу (если вообще хранится)?

Такая операция недопустима. Это следует из того, что не должно быть боксинга.
Re[7]: Типы значений и коллекции
От: Ocelot  
Дата: 24.09.10 21:28
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Такая операция недопустима. Это следует из того, что не должно быть боксинга.


Вооот! Хотя у автора такого требования нет.
Более того, исходя из требования использования специального значения Undefined и наличия операции "Удаление и очистка" (когда вместо имеющегося значения по ключу будет этот самый Undefined и положен) следует, что тип того, что лежит в коллекции по ключу, запросто может меняться. А раз тип заранее не известен, то непосредственно типизированный вызов обобщенного метода сделать не получится.
Это именно и есть противоречие в концепции, о котором я уже говорил.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.