Здравствуйте, Cyberax, Вы писали:
_FR>>>>Это почему? List<int> — параметризованный примитивным типом List<> C>>>Нет. Ты параметризуешь ОБЕРТКОЙ для типа int, то есть настоящим полноценным объектом. Просто это скрывают синтаксическим сахаром. EC>>А можно подробнее? Что понимается под обёрткой? C>http://msdn.microsoft.com/msdnmag/issues/1200/dotnet/ — см. по слову "boxing".
Можно вопрос? А за что минусы?
Здравствуйте, Cyberax, Вы писали:
_FR>>>>>Это почему? List<int> — параметризованный примитивным типом List<> C>>>>Нет. Ты параметризуешь ОБЕРТКОЙ для типа int, то есть настоящим полноценным объектом. Просто это скрывают синтаксическим сахаром. EC>>>А можно подробнее? Что понимается под обёрткой? C>>http://msdn.microsoft.com/msdnmag/issues/1200/dotnet/ — см. по слову "boxing". C>Можно вопрос? А за что минусы?
А ты считаешь, что все так прям должны быть согласны с тобой? С Тем, что создавая тип List<int> я "параметризую его ОБЕРТКОЙ для типа int"?
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, VladD2, Вы писали:
VD>А то получается идиотизм. С проект созданный под эгидой МС Ресерч не знакомы не только Хейльсберг
Получается действительно идиотизм. На прямо заданный вопрос Хейлсберг дал однозначный ответ — да, он смотрел на Немерле. Но этот факт разрушает стройную теорию мирового заговора против Немерле, так что тем хуже для фактов.
Здравствуйте, AndrewVK, Вы писали:
_FR>>А может ли определение "второго метода" браться из extension-классов?
AVK>Нет. А зачем?
Есть, например, некий генератор, который создаёт мне несколько классов. Генератор предоставляет мне возможность расширить поведение сгенерированного класса за счёт частичных методов. А если все эти методы должны быть одинаковыми?
Часто это нужно в конструкторе. Можно задать базовый для генерированного класса класс (что некоторые генераторы позволяют), но пользоваться виртуальными методами в конструкторе мне не нравится.
Кстати, partial metod может быть определён не в том же классе, в в базовом (это опять-таки может пригодиться, когда можно задать базовый тип для сгенерированного класса).
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Продолжу. По поводу Немерле тут уже сказали. Еще я задал вопрос о возможности добавления паттерн-матчинга. Потом мы немножко поговорили о F#, в котором онный есть. Ответа конкретного я так и не получил. Т.е. вопрос добавления обсуждается, но никаких конкретных планов пока нет.
Далее, эти самые кортежи с глобальной доступностью. С очень большой вероятностью они появятся, как только появится оказия с поменянием рантайма. Т.е., ориентировочно, что то появится а .NET 4.0. Но Хейлсберг ничего не обещает.
Потом я задал вопрос — когда компилятор шарпа будет написан на шарпе. В ответ он сказал, что ему никто не даст на это денег, потому что в плане конечного результата это мало что изменит.
По поводу наличия парсера шарпа в составе платформы — крайне сложно создать AST, которое бы подходилодля всех (или большей части) задач. Но какие то работы на эту тему ведуться.
По поводу расширяемости компилятора (в плане кодогенератора прежде всего). Во-первых, (я вам этого не говорил ) код компилятора шарпа весьма грязен и сделать к нему публичный API непросто. Во-вторых Хейлсберг не хочет связывать себе руки необходимостью обеспечения совместимости с monkey code, который напишут прикладники.
Здравствуйте, AndrewVK, Вы писали:
AVK>Получается действительно идиотизм. На прямо заданный вопрос Хейлсберг дал однозначный ответ — да, он смотрел на Немерле.
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, migel, Вы писали:
M>>Я тебе показал что реально быстрее — возражения будут? Или "богатеии копеек не считают" WH>Ничего ты не показал.
Совсем совсем ничего? жаль
Ну а если по честному то стастистика показывает правильность решения введения двух команд
например на System.dll
частота использования ldc_i4_0...ldc_i4_8 на порядок больше ldc_i4_N (~6.6% против 0.67%)
Здравствуйте, migel, Вы писали:
M>Совсем совсем ничего? жаль
Имеено так.
Откуда берутся тормоза так и небыло показано.
Идинственное место в котором можно получить прирост это уменьшения времени которое нужно для того чтобы считать сборку с винта благодоря тому что ldc.i4.0 компактней чем просто ldc.i4.
M>Ну а если по честному то стастистика показывает правильность решения введения двух команд
Да ничего она не показывает.
Тогоже эффекта можно легко добится не корежа модель системы.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Cyberax, Вы писали:
C>Как ты собираешься объединять типы с разной семантикой? У примитивных типов — передача по значению, а у объектов — по ссылке. В этом коренное отличие.
.NET 2 с этим прекрасно справляется.
C>Не ортогонально. Оно у тебя просто прозрачно боксирует value-типы — и "возвращаемся обратно на клетку 1", получая весь оверхед, связаный с объектами. C>Я как-то уже тут спорил с кем-то об этом. Поискать?
value типы в генерики можно засовывать без боксинга.
Совсем. Это не убогая жаба. Тут все работает как надо.
У нас ведь есть JIT который прекрасно может сгенерить нужный код для value параметров
C>Ничем бы это не помогло. Точно так же, можно было бы для боксирующей обертки просто добавить нужные методы. Это не требует изменения VM, а только стандартной библиотеки.
Нет никакой ложки... вренее боксинга.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Cyberax, Вы писали:
WH>>Не путай .NET и жабу. Это в жабе недогенерики, а в .NET2 все по честному. C>Что по-честному? Хочешь сказать, что можно параметризовать незабоксироваными VT?
Именно так.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, migel, Вы писали:
M>>Совсем совсем ничего? жаль WH>Имеено так. WH>Откуда берутся тормоза так и небыло показано. WH>Идинственное место в котором можно получить прирост это уменьшения времени которое нужно для того чтобы считать сборку с винта благодоря тому что ldc.i4.0 компактней чем просто ldc.i4.
Зыж дык не надо аргумент с потока считывать ы?
Или сие не аргумент?
Здравствуйте, Cyberax, Вы писали:
C>Не ортогонально. Оно у тебя просто прозрачно боксирует value-типы — и "возвращаемся обратно на клетку 1", получая весь оверхед, связаный с объектами.
Вообще-то это не так.
Вот доказательство:
Как сделать на c# обобщенную арифметику? Это достаточно просто, хотя и выглядит весьма уродливо. Но работает.
Можно построить целую иерархию "классов типов":
public interface CComparable<T>
{
bool GT(T a, T b);
bool LT(T a, T b);
bool Eq(T a, T b, T eps);
}
public interface CEq<T>
{
bool Eq(T a, T b);
bool NonEq(T a, T b);
}
public interface COrdered<T> : CComparable<T>, CEq<T>
{
bool GTorEq(T a, T b);
bool LTorEq(T a, T b);
}
public interface CNumber<T> : CComparable<T>
{
T Add(T a, T b);
T Sub(T a, T b);
T AddNeutral { get;} // 0
T Prod(T a, T b);
T ProdNeutral { get;} // 1
T Abs(T a);
T Negate(T a);
T Signum(T a);
}
public interface CFractional<T> : CNumber<T>
{
T From(double a);
T From(float a);
T Quot(T a, T b);
T Inv(T a);
}
public interface CInteger<T> : CNumber<T>, COrdered<T>
{
T From(int a);
T From(long a);
T Div(T a, T b);
T Mod(T a, T b);
}
public interface CReal<T> : CFractional<T>
{
T Sqr(T a);
T Sqrt(T a);
}
А теперь, написать имплементации, например RealDouble:
public struct RealDouble : CReal<double> // обратите внимание на struct
{
#region CFractional<double> Members
public double From(double a)
{
return a;
}
public double From(float a)
{
return a;
}
public double Quot(double a, double b)
{
return a / b;
}
public double Inv(double a)
{
return 1 / a;
}
#endregion
#region CNumber<double> Members
public double Add(double a, double b)
{
return a + b;
}
public double Sub(double a, double b)
{
return a - b;
}
public double AddNeutral
{
get { return 0.0; }
}
public double Prod(double a, double b)
{
return a * b;
}
public double ProdNeutral
{
get { return 1.0; }
}
public double Abs(double a)
{
return Math.Abs(a);
}
public double Negate(double a)
{
return -a;
}
public double Signum(double a)
{
return Math.Sign(a);
}
#endregion
#region CComparable<double> Members
public bool GT(double a, double b)
{
return a > b;
}
public bool LT(double a, double b)
{
return a < b;
}
public bool Eq(double a, double b, double eps)
{
return Math.Abs(a - b) < eps;
}
#endregion
#region CReal<double> Members
public double Sqr(double a)
{
return a * a;
}
public double Sqrt(double a)
{
return Math.Sqrt(a);
}
#endregion
}
Теперь сделаем комплексные числа:
public struct Complex
{
public Complex(double re, double im)
{
Re = re;
Im = im;
}
public double Re;
public double Im;
public static Complex operator +(Complex a, Complex b)
{
return new Complex(a.Re + b.Re, a.Im + b.Im);
}
}
public struct Complex<T, C>
where C : struct, CReal<T>
{
static C c = new C();
public Complex(T re, T im)
{
Re = re;
Im = im;
}
public T Re;
public T Im;
public static Complex<T, C> operator +(Complex<T, C> a, Complex<T, C> b)
{
return new Complex<T, C>(c.Add(a.Re, b.Re), c.Add(a.Im, b.Im));
}
}
Идея ясна? Если правы Вы, то во втором случае будут виртуальные вызовы (даже хуже, потому что CReal<T> это интерфейс)
Я же утверждаю, что никаких виртуальных вызовов не будет, более того, функция будет заинлайнена JIT.
Теперь пишем вот такой вот тест:
class Program
{
static void Main(string[] args)
{
System.Threading.Thread.Sleep(2000); // дадим время рантайму.
Stopwatch sw = new Stopwatch();
int count = 100000000;
Complex c1 = new Complex();
Complex c2 = new Complex(0, 1);
Complex<double, RealDouble> gc1 = new Complex<double, RealDouble>();
Complex<double, RealDouble> gc2 = new Complex<double, RealDouble>(0, 1);
for (int i = 0; i < count/1000; i++) // это для того, чтобы исключить из замеров JIT-компиляцию.
{
c2 = c2 + c1;
}
for (int i = 0; i < count/1000; i++)
{
gc2 = gc2 + gc1;
}
sw.Start();
for (int i = 0; i < count; i++)
{
c2 = c2 + c1;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int i = 0; i < count; i++)
{
gc2 = gc2 + gc1;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
Console.ReadLine();
}
}
Компилируем в Release, запускаем без отладчика.
.NET Framework 2.0.50727
Xeon-A(Prestonia) X2, 2666 MHz
Получаем вот что:
2457
2454
quod erat demonstrandum.
... << RSDN@Home 1.2.0 alpha rev. 655>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Задумался вот о чем, а можно ли это сделать на Немерле?
Попробовал сам поковыряться в Немерле и даже попробовать кое-что на написать, вот что получилось:
public class Vector3D ['a]
{
public mutable p : 'a * 'a * 'a;
public static @+ (a : Vector3D ['a], b : Vector3D ['a]) : Vector3D ['a]
{
def res = Vector3D.['a]();
res.p = (a.p[0].Sum(b.p[0]), a.p[1].Sum(b.p[1]), a.p[2].Sum(b.p[2]));
res
}
public static Sum(this a : 'a, b : 'a) : 'a
{
def t = (a, b);
match (t)
{
| (x, y) when (x is int && y is int) => (x :> int + y :> int) :> 'a
// ... make the same for other types
}
}
}
public class Test
{
public static Main() : void
{
def v1 = Vector3D.[int]();
def v2 = Vector3D.[int]();
v1.p = (1, 1, 1);
v2.p = (1, 2, 3);
def v = v1 + v2;
printf("(%d, %d, %d)\n", v.p[0], v.p[1], v.p[2]);
}
}
Получилось все равно кривовато, т.к. для своих типов надо перегрузив '+' добавить строчку в методе Sum. Ну и само по себе добавлять метод в object я думаю не очень хорошая практика.
((lambda (x) (list x (list 'quote x))) '(lambda (x) (list x (list 'quote x))))