Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, Сергей Губанов, Вы писали:
ГВ>Интересное определение, хотя и глюкавое. ИМХО, разумеется. Опять же ИМХО, но определение "мощности" должно прямо или косвеннно включать в себя понятие "времени", просто чтобы не выбиваться из устоявшейся трактовки.
Значит о мощности множества целых чисел или мощности континуума Вы не слышали? По Вашему слово мощность — это только dE/dt? Я использовал термин мощность в теоретико множественном смысле, а не в смысле термина мощность из физики.
ГВ>Что же касается "размерности пространства всевозможных программ", то тут уже правильно говорили, что машины Тьюринга хватит на всё, на что можт хватить компьютера.
Вы не поняли о чем речь. Когда мы из ЯВУ что-то мысленно удаляем, то мы можем нечаянно превратить его в другой ЯВУ, который уже не будет уметь программировать машину Тьюринга. (Просто мысленно удалите указатели и оператор NEW и Вы лишитесь не только динамических структур, но и бесконечной ленты). Опять же вопрос с удалением из ЯВУ процедурных переменных (указателей на функции), удалите их и Вы сможете написать только такой код, который может использовать для своей работы только другой уже написанный ранее код, а еще не написанный код он использовать не сможет, в то время как с помощью процедурных переменных (call back function) можно писать код, который сможет использовать для своей работы другой код еще не написанный в момент создания этого кода. Тем самым Вы сможете строить динамически расширяемые модульные системы. Кстати, про модульность: удалите из ЯВУ сборщик мусора — тогда вы лишите этот язык возможности писать модульные программы (потому что только runtime system знает какие модули загружены и только она может принять решение об утилизации памяти).
Здравствуйте, Сергей Губанов, Вы писали:
ГВ>>Интересное определение, хотя и глюкавое. ИМХО, разумеется. Опять же ИМХО, но определение "мощности" должно прямо или косвеннно включать в себя понятие "времени", просто чтобы не выбиваться из устоявшейся трактовки. СГ>Значит о мощности множества целых чисел или мощности континуума Вы не слышали? По Вашему слово мощность — это только dE/dt? Я использовал термин мощность в теоретико множественном смысле, а не в смысле термина мощность из физики.
Хех. Вакуумживущий сфероконь в чистом виде! А известно ли тебе, что программы реализуются в ограниченное время (T), в ограниченном пространстве (V = Freq*RAM*HDD ) и ограниченными же силами (программистами — E). Я совершенно не спорю, что с абстрактной теоретической точки зрения шаблоны — суть не более чем типизированные макросы (гусары, молчать!), но от этого не меняется их оценка с точки зрения практической. А практика имеет дело с ограниченными T, V и E. И в этом контексте "физическая" интерпретация понятия "мощность инструмента" имеет первостепенное значение. Почему? Потому что если вылететь за пределы хоть одного из этих параметров, то конечной программы просто не будет. Сечёшь? Это глупость — выкидывать контекстные переменные из рассуждений об инструментах, сводя оценки к чистым абстракциям!
И вот в таком контексте (E < Emax, V < Vmax, T < Tmax, где любой Xmax о-о-очень далёк от бесконечности, более того — всеми силами стремится к нулю) шаблоны очень даже важны, поскольку дают в руки инструмент снижения как минимум одного, а зачастую — и всех трёх параметров по отношению к той же программе, но реализованной методом copy&paste. Скажу больше — все наши игры в "Язык1 vs. Язык2" крутятся как раз вокруг оптимизации этих самых трёх параметров.
Пойми главное — абстрактной программы не было, нет и никогда не будет. Я ничего не имею против очень красивой модели о совершенстве ненаписанного, но всё, что есть — есть конкретные вещи, реализованные для конкретных целей в конкретные сроки и конкретными инструментами. Понимаешь? Они — есть, а абстрактной программы — нет. Точно также, как нет чистого листа после того, как на нём нанесена первая черта. Но! Мы можем называть некоторые элементы программы "абстракциями" — так удобнее, поскольку они есть с точки зрения програмиста: их можно скомпилировать, отредактировать и т.п. Т.е., они есть, как оформленные информационные объекты. А вот абстрактной программы — нет как нет.
Соответственно, рассуждать об абстрактной мощности языка в предлагаемых тобой терминах, хоть и любопытно, но по меньшей мере — бессмысленно. У нас-то спор идёт о реальных программах и языках. Он ведётся реальными людьми, решающими реальные задачи.
Вот потому я и попытался прямо подтолкнуть тебя к формулировке понятия "мощность", применимого в реальном контексте. Смекаешь? Да, я знаю, что сам по себе термин "мощность" может употребляться для обозначения разных показателей, но вот по отношению к инструменту, каковым является любой ЯВУ, ИМХО, лучше всего употреблять его как оценку dE/dt.
ГВ>>Что же касается "размерности пространства всевозможных программ", то тут уже правильно говорили, что машины Тьюринга хватит на всё, на что можт хватить компьютера.
[Пожрато относительно вычетов. Шоколадный сфероконь.]
Да, я понял, о чём ты говорил. И даже понял — почему это мне не понравилось. И не только мне. И даже сформулировал это выше.
PS. Разумеется — ничего личного.
... << RSDN@Home 1.1.3 stable >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Сергей Губанов, Вы писали:
СГ>(Просто мысленно удалите указатели и оператор NEW и Вы лишитесь не только динамических структур, но и бесконечной ленты).
О как? Что же там уж мысленно. В Яве и шарпе указатели удалены очень даже явно. new правда остался, но все же. И как не странно языки от этого ничего не потеряли.
Может быть пора начать думать шире? Указатели — это возможность которая может быть легко заменена другой возможностью. Вместо указателей приходят ссылки. Это другой взгял на мир.
СГ> Опять же вопрос с удалением из ЯВУ процедурных переменных (указателей на функции), удалите их и Вы сможете написать только такой код, который может использовать для своей работы только другой уже написанный ранее код, а еще не написанный код он использовать не сможет,
Опять же берем Яву и ее инерфейсами. Назвать интерфейсы указателями на функции вряд ли можно. Но они опять же заменяют указатели на методы.
Более того. Данные заявления базируются на довольно сомнительных предположениях. Одно из них заключается в том, что код обязан быть скомпилирован в исполняемый код. И что он не может модифицироваться в последствии. А на самом деле без проблем можно делать воплощение полиморфного кода только тогда, когда становятся все обрабатываемые им типы. Например, можно создать полиморфный байт-код и производить начальную компиляцию в енго. А уже потом когда появляется необходимоть произвести воплощение этого кда с конкретными типами проивзодить компиляцию в машинный код. Так что это очередная плотно засевшая догма.
СГ> в то время как с помощью процедурных переменных (call back function) можно писать код, который сможет использовать для своей работы другой код еще не написанный в момент создания этого кода.
И этому примитивизму вы хотите учить детей? Указатели, указатели на функции... это же копание на уровне ассемблера.
Почему в ваших словах нет слышно таких терминов как абстракция, полиморфизм? Почему указатели? Что за каменный век?
СГ> Тем самым Вы сможете строить динамически расширяемые модульные системы. Кстати, про модульность: удалите из ЯВУ сборщик мусора — тогда вы лишите этот язык возможности писать модульные программы (потому что только runtime system знает какие модули загружены и только она может принять решение об утилизации памяти).
Жаль что об этом вашем открытии не слышали те кто разрабатывали COM и Корбу. Они то по незнанию взяли да и реализовали модульные, я бы даже сказал компонентные технологии не закладываясь на сборку мусора.
ЗЫ
В общем, страшно за подрастающее поколение. Если их будут учить таким вот "знаниям" то мы получим очередную партию ламеров.
Поймите — это ваших рук дело куча долболомов кое-как выучивших Бэйсик или Дельфи и занимающихся накидыванием кнопок на формы. Все это потому что вы не тому учите детей. Учите умению выделять абстракцию. Учите не замечать неважных деталей. Не скативаться до понятий указателей. Учите писать полиморфный код, а не применять указатели на процедуры. Учите выделять общие моменты, а не забивайте голову детей подробностями реализации виртуальных таблиц и дескрипторов типов.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Вы не поняли о чем речь. Когда мы из ЯВУ что-то мысленно удаляем, то мы можем нечаянно превратить его в другой ЯВУ, который уже не будет уметь программировать машину Тьюринга. (Просто мысленно удалите указатели и оператор NEW и Вы лишитесь не только динамических структур, но и бесконечной ленты).
Обманываешь. Все, что нам нужно — это пара функций и операторов над ними, напомню определение рекурсивных функций:
O(x) = 0
s(x) = x + 1
Itn(x1,...xn) = xt
Оператор примитивной рекурсии:
f = R(g,h), f определяется как:
f(x1,x2,...,xn,0) = g(x1,...,xn)
f(x1,x2,...,xn,y+1) = h(x1,x2,...,xn,y,f(x1,x2,...,xn,y))
Оператор минимизации:
my = M(f), my определяется как:
my(x1,...,xn) = min y, что f(x1,...,xn-1,y) = xn
Оператор суперпозиции:
g = Sm(f,f1,...,fm), g определяется как:
g(x1,....,xn) = f(f1(x1,...,xn),...,fm(x1,...,xn))
Замечу, что для вычиления этих функций оператор NEW нам совершенно не нужен. Никаких указателей!
За точность не ручаюсь, давно это было. Доказательство эквивалентности вычислимости через машину Тьюринга и через рекурсивно-вычислимые функции оставляю в качестве домашнего задания
Здравствуйте, Сергей Губанов, Вы писали: СГ>Так убери еще и goto. Что изменилась мощность языка? То-то, а от шаблонов она не меняется.
Ну тогда я, в общем, заканчиваю. Твоя неспособность видеть порочность собственных аргументов превосходит пределы моего воображения. Ты про RISC-ассемблер прочитал? Понял?
В последний раз объясняю: шаблоны — ничуть не хуже чем циклы, процедурные переменные, да и любые черты, присущие языку высокого уровня. А ты их критикуешь ровно потому, что их нет в Обероне. А оберон — по определению идеален. Ну так вот не идеален он нифига. Поскольку есть языки с более высокой мощностью. А мощность языка определяется только тем, насколько мало программисту нужно колотить по клавишам. Точка. Вся твоя философия про "необходимые" и "избыточные" конструкции абсолютно некомпетентна. Почитай классиков, посмотри на другие языки.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, VladD2, Вы писали:
VD>...Указатели...
Ну, вот, пожалуйста. Вами была написана такая гневная тирада и все из-за слова "указатель". У Вас просто есть жесткая ассоциация "указатель = адрес". Спрашивается откуда у Вас эта ассоциация, как не из языка Си/Си++? В оберонах указатели есть, а вот адресов нет, понимаете разницу?
Здравствуйте, Сергей Губанов, Вы писали:
К>>>Если в спецификации не прописано явно, что with всегда выбирает most derived ветку, то порядок проверок становится существенным. К>>>В этом отличие от case: целочисленная переменная не может быть равна нескольким разным ключевым значениям, а полиморфный объект — может принадлежать разным классам одновременно.
К>>Ну и разумеется, в случае множественного наследования никакое most derived не спасёт в принципе.
СГ>И так, в наихудшем случае (т.е. когда ответ будет отрицательный), время необходимое для работы инструкции WITH определяется формулой СГ>
СГ>t = const*H*Log(N)
СГ>В то время как цепочка if-dynamic_cast-else будет работать за время: СГ>
СГ>T = const'*H*N
СГ>где H в первой и второй формуле одинаковы (надо же проверить все варианты!)
Дело не во времени работы, а в устранении неоднозначностей. Если объект одновременно принадлежит нескольким иерархиям одновременно, то выбор между несколькими классами — дело произвольное.
// общая базаclass A { ... };
// от которой вырастают две иерархииclass B1 : public A { ... };
class C1 : public A { ... };
// что-то-там-далеко...class D : public B7, public C5 { ... };
void foo(A* p)
{
if(dynamic_cast<B1*>(p)) { cout << "b" << endl; }
else
if(dynamic_cast<C1*>(p)) { cout << "c" << endl; }
}
void bar(A* p)
{
if(dynamic_cast<C1*>(p)) { cout << "c" << endl; }
else
if(dynamic_cast<B1*>(p)) { cout << "b" << endl; }
}
bool xyz_t(type_info const* t)
{
// вариант с поиском в глубинуtype_info const *ti[2] = { typeid(B1), typeid(C1) }; // можно отсортироватьint i = find(ti, ti+2, t)-ti; // можно бинарным поискомswitch(i)
{
case 0: cout<<"b"<<endl; return true;
case 1: cout<<"c"<<endl; return true;
default: return false;
}
}
void xyz1(D* p)
{
// в C++ нет возможности пробежать по иерархии, но сделаем это руками (мы же знаем реальный тип аргумента ;)
xyz_t(typeid(D)) || // для простоты, воспользуемся булевым оператором ИЛИ-ИНАЧЕ
// равномерно спускаемся в глубину
xyz_t(typeid(B7)) ||
xyz_t(typeid(C5)) ||
xyz_t(typeid(B6)) ||
xyz_t(typeid(C4)) ||
xyz_t(typeid(B5)) ||
xyz_t(typeid(C3)) ||
xyz_t(typeid(B4)) ||
xyz_t(typeid(C2)) ||
xyz_t(typeid(B3)) ||
xyz_t(typeid(C1)) || // <-- совпало!
xyz_t(typeid(B2)) ||
xyz_t(typeid(B1)) ;
}
void xyz2(D* p)
{
xyz_t(typeid(D)) ||
// ветка B
xyz_t(typeid(B7)) ||
xyz_t(typeid(B6)) ||
xyz_t(typeid(B1)) || // <-- совпало!
// ветка C
xyz_t(typeid(C5)) ||
xyz_t(typeid(C4)) ||
xyz_t(typeid(C1)) ;
}
void xyz3(D* p)
{
xyz_t(typeid(D)) ||
// ветка C
xyz_t(typeid(C5)) ||
xyz_t(typeid(C4)) ||
xyz_t(typeid(C1)) || // <-- совпало!
// ветка C
xyz_t(typeid(B7)) ||
xyz_t(typeid(B6)) ||
xyz_t(typeid(B1)) ;
}
main()
{
D* p = new D;
foo(p); // b
bar(p); // c
xyz1(p); // c
xyz2(p); // b
xyz3(p); // cdelete p;
}
Здравствуйте, Sinclair, Вы писали:
S>А мощность языка определяется только тем, насколько мало программисту нужно колотить по клавишам. Точка. Вся твоя философия про "необходимые" и "избыточные" конструкции абсолютно некомпетентна. Почитай классиков, посмотри на другие языки.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Ну, вот, пожалуйста. Вами была написана такая гневная тирада и все из-за слова "указатель". У Вас просто есть жесткая ассоциация "указатель = адрес". Спрашивается откуда у Вас эта ассоциация, как не из языка Си/Си++? В оберонах указатели есть, а вот адресов нет, понимаете разницу?
Отнюдь! В С++ есть указатели и ссылки, а адресов тоже нет
Более того, некоторые указатели — это вообще не адреса, а бог знает что. Например, указатель на виртуальную функцию-член класса с виртуальным наследованием.
Так что если у кого жёсткая ассоциация — так это у тебя: "С++ — адрес — хреново".
Здравствуйте, Кодт, Вы писали:
К>.. Если объект одновременно принадлежит нескольким иерархиям одновременно, то выбор между несколькими классами — дело произвольное.
Правда Ваша, для множественного наследования оператора WITH быть не может, он существует только в случае одиночного наследования.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Сергей Губанов, Вы писали:
СГ>>Ну, вот, пожалуйста. Вами была написана такая гневная тирада и все из-за слова "указатель". У Вас просто есть жесткая ассоциация "указатель = адрес". Спрашивается откуда у Вас эта ассоциация, как не из языка Си/Си++? В оберонах указатели есть, а вот адресов нет, понимаете разницу?
К>Отнюдь! В С++ есть указатели и ссылки, а адресов тоже нет
Адресов значит нет. Может и адресной арифметики в Си/Си++ нет? А это что:
int p* = &a[5];
if( a[8] != *(p+3) ) катастрофа();
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Ну, вот, пожалуйста. Вами была написана такая гневная тирада и все из-за слова "указатель". У Вас просто есть жесткая ассоциация "указатель = адрес". Спрашивается откуда у Вас эта ассоциация, как не из языка Си/Си++?
Указатели — это вредная (по крайней мере на стадии первичного обучения) идиома. Есть множество языков не использующих ее и при этом ни сколички не страдающих. Примеры все те же Ява, Шап, Питон.
СГ>В оберонах указатели есть, а вот адресов нет, понимаете разницу?
Еще раз повторяю. Ваш любимый оберон — это устаревшее до рождения дитя. То что в нем есть подобные несоотвествия (наличие указателей при отсуствии адресной арифметики) только подтверждают его непрактичность.
Если вам интересно, могу продемонстрировать как современные языки живут вообще без указателей. Вот, к примеру, обобщенный код быстрой сортировки и двоичного поиска на шарпе:
using System;
// Объявления делегата. Делегат - это ОО-замена указателю на функции.
// Они полностью типобезопасны и погут хнанить контекст конкретного объекта.delegate int Compare<T>(T x, T y);
class Program
{
// Дженерики - одна из самых простых реализаций принципов
// обобщенного программирования среди типизированных ИЯ.
// Дженери- могут быть даже делегаты. Так параметр compare
// - это дженерик-дерегат. С его помодью можно передать ссылку
// на функцию сравнения элементов.public static void Sort<T>(T[] array, Compare<T> compare)
{
Sort(array, 0, array.Length - 1, compare);
}
// Перегрузка методов. Статический полиморфизм в дейстии.public static void Sort<T>(T[] array, int left, int right, Compare<T> compare)
{
int i = left;
int j = right;
T center = array[(left + right) / 2];
while (i <= j)
{
while (compare(array[i], center) < 0)
i++;
while (compare(array[j], center) > 0)
j--;
if (i <= j)
{
T x = array[i];
array[i] = array[j];
array[j] = x;
i++;
j--;
}
}
if (left < j)
Sort(array, left, j, compare);
if (right > i)
Sort(array, i, right, compare);
}
public static int BinarySearch<T>(T[] array, T value, Compare<T> compare)
{
return BinarySearch(array, 0, array.Length, value, compare);
}
public static int BinarySearch<T>(T[] array, int lo, int hi, T value, Compare<T> compare)
{
while (lo <= hi)
{
int i = (lo + hi) / 2;
int cmpResult = compare(array[i], value);
if (cmpResult == 0)
return i;
else if (cmpResult < 0)
lo = i + 1;
else
hi = i - 1;
}
return ~lo;
}
static void Main(string[] args)
{
int[] array = new int[] { 8, 2, 9, 1, 23, 245, 34, 3, 4 };
// Безымянные методы полезны как на практике, так и в целях
// применения функционального подхода.
Compare<int> compare = delegate(int x, int y) { return x - y; };
// Подбор функции ведется на базе типов аргументов.
Sort(array, compare);
int index = BinarySearch(array, 23, compare);
// Шарп язык строгий, но гибкий. Так можно складывать числа со
// строками. Это возможно из-за того, что в языке можно перегружать
// операторы. Строкая, в прочем как и все остальное - это тоже класс.
Console.WriteLine("Index is " + index);
}
}
Заметьте, не одного указателя. Все концептуально чисто и очень понятно. Даже для указателей на функции есть прекрасная замена.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Кодт, Вы писали:
К>Более того, некоторые указатели — это вообще не адреса, а бог знает что. Например, указатель на виртуальную функцию-член класса с виртуальным наследованием.
Именно. И именно по этому, мне больше нравится идея делегата из Шарпа. Чистая и красивая абстракция.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Сергей Губанов: > > СГ>>Ну, вот, пожалуйста. Вами была написана такая гневная тирада и все из-за слова "указатель". У Вас просто есть жесткая ассоциация "указатель = адрес". Спрашивается откуда у Вас эта ассоциация, как не из языка Си/Си++? В оберонах указатели есть, а вот адресов нет, понимаете разницу? > > К>Отнюдь! В С++ есть указатели и ссылки, а адресов тоже нет > > Адресов значит нет. Может и адресной арифметики в Си/Си++ нет?
Здравствуйте, VladD2, Вы писали:
VD>Указатели — это вредная (по крайней мере на стадии первичного обучения) идиома.
Наоборот. Как показывает практика (info21), дети с легкостью пишут программы работающие с динамическими списками. Потому что это интуитивно понятно. А вот написание фортраноподобных алгоритмов — есть уже следующая ступень развития детского разума.
TYPE
List = POINTER TO ListDesc;
ListDesc = RECORD
Data: ....
Next: List;
END;
VD>Есть множество языков не использующих ее и при этом ни сколички не страдающих. Примеры все те же Ява, Шап, Питон.
Да что Вы такое говорите! Без указателей невозможны динамические структуры данных. Теже списки, например. Все наоборот: в Java нет не указателей на объекты, а там нет самих объектных переменных как таковых, любая объектная переменная в Java это и есть УКАЗАТЕЛЬ на объект, а не САМ объект.
VD>Если вам интересно, могу продемонстрировать как современные языки живут вообще без указателей. Вот, к примеру, обобщенный код быстрой сортировки и двоичного поиска на шарпе:
Указатели нужны для работы с динамическими структурами (время исполнения); а обобщенный код — статичен (время компиляции). Ваш пример не относится к делу.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Кодт, Вы писали:
К>>Более того, некоторые указатели — это вообще не адреса, а бог знает что. Например, указатель на виртуальную функцию-член класса с виртуальным наследованием.
VD>Именно. И именно по этому, мне больше нравится идея делегата из Шарпа. Чистая и красивая абстракция.
Которая называется — "процедурная переменная" и о которой я сто раз тут говорил. Если уж на то пошло, то Delphi вся на них построена...
Здравствуйте, VladD2, Вы писали:
VD>Указатели — это вредная (по крайней мере на стадии первичного обучения) идиома. Есть множество языков не использующих ее и при этом ни сколички не страдающих. Примеры все те же Ява, Шап, Питон.
Тут появляется другая идиома, value/reference типы. То есть, передаваемые по значению (копируемые) и по ссылке (разделяемые).
Она, конечно, более прозрачна для понимания — но тоже содержит ряд приколов (ошибкоопасностей):
* нечаянный разрыв связи: модификация переменной не доходит до партнёра
* нечаянное создание/сохранение связи: модификация, казалось бы, локальной копии уходит на сторону
Здравствуйте, Dervish, Вы писали:
D>Линковка не создаёт тормозов. Реально. Конечно, это зависит от проекта к проекту, но по моим субъективным ощущениям вряд ли линковка будет занимать более 10% от общего времени компиляции проекта. Это довольно быстрая и не накладная процедура.
Главная проблема линковки — в том, что её нельзя пустить распределённо
Скажем, проект распределённо компиляется за 5 минут, а потом 15 минут линкуется на твоей машине. Приятного мало.