LINUX.ORG.RU

[philosophy] В чем заключается революционность перехода от функциональщины к ООП?


1

0

Так уж повелось, что первый язык, который я изучал, был делфи. Потом всякие сишарпики, С++, лисп, и т.п. В итоге, как мне кажется, у меня ООП головного мозга. Когда возникала задача писать на С, я начал реализовавывать обьектную модель в этом языке.

«Стоп», сказал я себе и подумал. Почему сейчас все кругом вопят про ООП и про его архиполезность и архиправильность? Далее, по ходу раздумий, пришел к мысли, что все, что пишется с использованием ООПшной парадигмы, может быть написано и без нее.

Почему появились языки, которые взяли ООП за главенствующую идею (java, c#, етц)?

Неужели те преимущества, которые предлагает ООП (полиморфизм, инкапсуляция, наследование), дают прирост в эффективности, скорости написания программ, понимания их работы и поддержке? Здесь было бы интересно сравнить одну и ту же программу, написанную на С и на С++, чтобы узреть принципиальные архитектурные различия (может такие уже есть?).

Сухой остаток. ООП представляет из себя еще один уровень абстракции, который позволяет оперировать про проектировании не функциями, а обьектами. А неужели это так меняет дело и делает разработку более удобной?

Было бы интересно без срачей услышать компетентное мнение.

★★

Ответ на: комментарий от www_linux_org_ru

Где? в статье не нашел, в комментах?

В статье человек подумал использовать ленивость для того же, для чего используют макросы (withFile тот же), т.е. утверждал о взаимозаменяемости второго первым. Ну а в коментариях появились, помимо прочих, Peter Seibel и один из основателей Symbolic и раскрыли человеку глаза (он признал свою ошибку).

макросом, как минимум, можно по одному коду сгенерить другой код

да, всё верно, об этом и речь.

quasimoto ★★★★ ()
Ответ на: комментарий от dave

Присоединяюсь к вопросу, а что такое «ООП на замыканиях»?

SICP / 3 глава - рекомендую :) Для scheme есть даже ООП «фреймворки» на этой основе.

quasimoto ★★★★ ()
Ответ на: комментарий от LamerOk

Если исходников, что-нибудь в роде «const int n = 10;», то почему бы и нет? ))

Ну, для совсем на голову нездоровых можно и так:

MigMit:~ MigMit$ cat test.cpp
#include <iostream>
const int n =
#include "test.h"
;
int main() {
  std::cout << n << std::endl;
  return 0;
}
MigMit:~ MigMit$ cat test.h
10
MigMit:~ MigMit$ g++ test.cpp -o test
MigMit:~ MigMit$ ./test
10

Miguel ★★★★★ ()
Ответ на: комментарий от tailgunner

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

чтобы эти 2 случая имело смысл различать, должен существовать гипотетический, но реализуемый компилятор, который сможет «использовать это знание»

приведи пример такого компилятора

хинт: привести пример невозможно, если в том примере int foo(int) throw(); тебе придется загнать константы в сигнатуру либо прямо int foo(Int<0,15>) throw() либо через придумывание класса

естественно, исключаем из рассмотрения приемчики типа загнать дополнительную информацию не в сигнатуру, а в объектник например

Ты не сможешь определить Int<0, 15>, проверяемый на этапе компиляции, так что твое «нихрена компилятор не знает» просто нелепо.

ты о чем?

проверка введеного юзером значения будет, и в обоих примерах приведет к return;

однако разница в том, что во втором случае, если убрать рантаймовую проверку, то компилятор с этим может не согласится;

впрочем, g++ -Wall -Wextra молча соглашается с кодом

int f(int i) throw() { if(i==0) throw(123); return i; }

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

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от oh

А это точно будет на всех реализациях работать?

Да куды ж ему, на хрен, деться?

Miguel ★★★★★ ()
Ответ на: комментарий от LamerOk

А ты как думал? Думаешь, творение Влора будет белым и в костюмчике? ;))

в светло-сером в крапинку костюмчике :-) уже щас можно покритиковать код с mapcar

а трюки типа

#include <iostream>

const int n=
#include "/dev/stdin"
;

int main()
{
    std::cout << n;
    return 0;
}

мне как-то чужды

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от LamerOk

> Мы ждем от влора шаблон-телепат, предсказывающий ввод пользователя.

1. не будет от меня шаблона-телепата — тот шаблон позволяет всего лишь объяснить то, что |a+b+c+d+e|==|a+e+d+b+c|

2. шаблон будет, но не в этой ветке, сорри.

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от oh

> Ага, его только прочитать осталось.

ну а что ты хотел? тут у нас не Первый канал, так что обосрать не прочитав не получится.

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от quasimoto

Присоединяюсь к вопросу, а что такое «ООП на замыканиях»?

SICP / 3 глава - рекомендую :) Для scheme есть даже ООП «фреймворки» на этой основе.

Тогда понятно. Вообще, я в оригинале читал ту главу. Что-то такого термина не припомню.

dave ★★★★★ ()
Ответ на: комментарий от LamerOk

> Я всё еще жду реализации вот этого:

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

Я тоже этого жду.

tailgunner ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

>> Я сказал, что есть способ дать компилятору знать, какое значение ввел пользователь. Я _не_ говорил, способен ли какой-нибудь существующий компилятор использовать это знание.

должен существовать гипотетический, но реализуемый компилятор, который сможет «использовать это знание»

приведи пример такого компилятора

То есть ты сомневаешься в принципиальной вожзможности? O_O Почему?

Пример именно компилятора не приведу, но как минимум 2 тайпчекера для Python декларируют распознавание конструкций вида assert isinstance(obj, Foo) и использование их для вывода типа obj (PyDev и Pyntch). Надеюсь, принципиальной разницы между assert isinstance(obj, Foo) и if (0 <= v && v <= 15) ты не видишь?

Ты не сможешь определить Int<0, 15>, проверяемый на этапе компиляции, так что твое «нихрена компилятор не знает» просто нелепо.

ты о чем?

Я о том, что мне лично непонятно, что такое Int<0, 15>. Ты вроде претендуешь на то, что это целочисленный тип, ограниченный 0..15, присваивания которому _статичнески_ проверяются компилятором? Если да, то пример в студию. Если нет, то твой компилятор тоже нихрена не знает.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Я о том, что мне лично непонятно, что такое Int<0, 15>. Ты вроде претендуешь на то, что это целочисленный тип, ограниченный 0..15, присваивания которому _статичнески_ проверяются компилятором? Если да, то пример в студию. Если нет, то твой компилятор тоже нихрена не знает.

Интересно, а как с этим обстоят дела в Аде? Там можно объявлять такие типы, насколько помню. Может быть, их компиляторы достаточно умны, и некоторые статические проверки действительно делаются на этапе компиляции. Интересно было бы узнать мнение тех, кто работал с Адой, если таковые, вообще, читают этот топик, в чем я сильно сомневаюсь ;)

dave ★★★★★ ()
Ответ на: комментарий от dave

> Интересно, а как с этим обстоят дела в Аде?

Насколько я понимаю, там вводиться новый тип «целое 0..15», и для присваивания значению этого типа другого целого нужно явное преобразование. Т.е. примерно так же, как можно сделать в Си++.

tailgunner ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

>> Я сказал, что есть способ дать компилятору знать, какое значение ввел пользователь. Я _не_ говорил, способен ли какой-нибудь существующий компилятор использовать это знание.

чтобы эти 2 случая имело смысл различать, должен существовать гипотетический, но реализуемый компилятор, который сможет «использовать это знание»


Вы съезжаете с темы в идиотский разговор о возможностях компилятора по части оптимизаций.

Везде выше по топику выражение «компилятор знает» означает возможность _программиста_ использовать значение в вычислениях времени компиляции.

LamerOk ★★★★★ ()
Ответ на: комментарий от LamerOk

Конкретный пример:

#include <iostream>

int main(int argc, char **argv)
{
	int n;
	std::cin >> n;
	// Ритуал чёрной магии производится тут.
	static int array[n];
	return 0;
}

Всем всё понятно? ;)

LamerOk ★★★★★ ()
Ответ на: комментарий от LamerOk

> Вы съезжаете с темы в идиотский разговор о возможностях компилятора по части оптимизаций.

Не участвуй в идиотских разговорах, делов-то.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Так я и забочусь о том, чтобы разговор не стал идиотским. Разве не видно? :3

LamerOk ★★★★★ ()
Ответ на: комментарий от tailgunner

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

oh ()
Ответ на: комментарий от oh

> Т.е. ты говоришь что комплятор может (хоть и в теории) использовать значение, который пользователь должен будет ввести ПОСЛЕ компиляции?

Формально - да. Фактически, конечно, прогер просто скажет компилятору «мамой клянусь, значение будет таким-то».

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

> Формально - да.
Вот теперь покажи, как это возможно.
Код такой:
main {
n = input_from_user
...
Здесь компилятор должен _использовать_ значение n
...
}

Фактически, конечно, прогер просто скажет компилятору «мамой клянусь, значение будет таким-то».


Это если только 1 значение, а если несколько?

oh ()
Ответ на: комментарий от oh

> Вот теперь покажи, как это возможно.

http://www.linux.org.ru/jump-message.jsp?msgid=5034750&cid=5046401

Ты что, видишь там какую-то логическую дыру?

Фактически, конечно, прогер просто скажет компилятору «мамой клянусь, значение будет таким-то».

Это если только 1 значение, а если несколько?

А какая разница? Любой число, заранее известное прогеру:

if (0 <= val1 && val1 <= 15 && 0 <= val2 && val2 <= 16 /* ... */) {

/* здесь мы можем полагаться на то, что значения val и val2 ограничены */

}

Подозреваю, что возможно даже ограничить любое количество значений - операцией над массивом.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

> Ты что, видишь там какую-то логическую дыру?

/* Всё, здесь и далее - уже сообщили, что всегда (0 <= x < 16) */

Отлично, мы знаем что введенное значение будет меньше нуля, но значение мы не знаем, значит и использовать не можем.

/* здесь мы можем полагаться на то, что значения val и val2 ограничены */


Ограничены, да пожалуйста. Это можно и с помощью системы типов сделать. Сказать, что n - unsigned int, вот и ограничили. Но значение мы _использовать_ не может, нет его

oh ()
Ответ на: комментарий от oh

> Ограничены, да пожалуйста. Это можно и с помощью системы типов сделать

Это будет примерно то же самое, что написал я, только вместо if будет преобразование типа (потенциально бросающее исключение).

Но значение мы _использовать_ не может, нет его

Неужели?

if (n > 0) {

/* гарантированно не даст dvide-by-zero */ return 1./n;

}

А если по «использовать» ты имеешь в виду «использовать с целью $ЦЕЛЬ», то по крайней мере назови значение ЦЕЛЬ.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

> return 1./n;

И это будет вычисленно на этапе компиляции?
Где здесь *компилятор* использует n?

Можно if(n>0) убрать, можно поставить, дополнительно компилятор ничего посчитать не сможет.

oh ()
Ответ на: комментарий от tailgunner

> ты имеешь в виду «использовать с целью $ЦЕЛЬ», то по крайней мере назови значение ЦЕЛЬ.

режим К.О. = старт

Любое значение, известное на момент компиляции, можно использовать в вычислениях времени компиляции.

режим К.О. = стоп

Простейший пример я привел выше. Если забыл, напоминаю, - объявить статический массив заданной размерности. ;)

LamerOk ★★★★★ ()
Ответ на: комментарий от LamerOk

>> ты имеешь в виду «использовать с целью $ЦЕЛЬ», то по крайней мере назови значение ЦЕЛЬ.

режим К.О. = старт

Любое значение, известное на момент компиляции, можно использовать в вычислениях времени компиляции.

В этом режиме оно использоваться вполне может.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Ну и как может использоваться _еще не введеное_ (и, следовательно, неизвестное) значение во время компиляции?

Хотеть! :D

LamerOk ★★★★★ ()
Ответ на: комментарий от LamerOk

if (n == 2) return n/2; /* оптимизируется в return 1 */

Причем это тривиально и уже сейчас возможно %) Наверное, ты о чем-то другом хотел спросить?

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Это то, про что я говорил: все значения по одному перебирать

oh ()
Ответ на: комментарий от tailgunner

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

в то время как я предлагаю в общем-то небольшое изменение, которое полезно

вот те 2 функции, специально чуть переписаны так, чтобы их можно было сравнить построчно

int foo(int); int bar(int); int baz(int);

void f() 
{ 
  int x = input_some_number();  
  if(x < 0 || x > 15) return;  /// вместо этой строки
  int u=foo(x); 
  int v=bar(x); 
  int w=baz(x); 
  ... 
}
int foo(Int<0,15>); int bar(Int<0,15>); int baz(Int<0,15>);

void f() throw()
{ 
  int tmp=input_some_number(); Int<0,15> x; 
  try{ x=Int<0,15>(tmp); } catch(OutOfRange) { return; } /// работает эта строка
  int u=foo(x); 
  int v=bar(x); 
  int w=baz(x); 
  ... 
}

Ты вроде претендуешь на то, что это целочисленный тип, ограниченный 0..15, присваивания которому _статичнески_ проверяются компилятором?

чуда нет — присваивание из int в Int<0,15> кидает исключение; профит *только* в том, что забыть написать строку с if нам никто не помешает, а забыть написать строку с try помешает нормальный компилятор (который следит за исключениями)

еще более умный компилятор мог бы даже принимать такое:

int foo(Int<0,15>); int bar(Int<0,15>); int baz(Int<0,15>);
 
void f() throw()
{  
  int x = input_some_number();   
  if(x < 0 || x > 15) return;  
  int u=foo(x);  
  int v=bar(x);  
  int w=baz(x);  
  ...  
}

но окупятся ли затраты на столь умный компилятор (и будет ли он достаточно демократичен — т.е. достаточно ли просто будет добавлять свои подобного рода проверки) — я не знаю

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от LamerOk

> Ага!

http://www.linux.org.ru/jump-message.jsp?msgid=5034750&cid=5049774

А что «ага»? Такое использование сейчас невозможно, но я не вижу причин, по которым его нельзя реализовать (за исключением тотальной бесполезности). Напоминаю, что изначально использование введенных юзером значений было упомянуто в разговоре о проверке типов.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

> Ты вроде претендуешь на то, что это целочисленный тип, ограниченный 0..15, присваивания которому _статичнески_ проверяются компилятором?

одного взгляда на код с «catch(OutOfRange)» должно было бы хватить, чтобы понять, что это не так

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от tailgunner

> Формально - да. Фактически, конечно, прогер просто скажет компилятору «мамой клянусь, значение будет таким-то»

«мамой клянусь» не годится; прогер должен предъявить доказательство, которое компилятор может принять, а может и найти в нем ошибки

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

>> прогер просто скажет компилятору «мамой клянусь, значение будет таким-то»

«мамой клянусь» не годится

В роли «мамой клянусь» - обычный if.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

> В роли «мамой клянусь» - обычный if.

пиши свой вариант кода с функциями foo bar baz и говори, как компилятор поймет, что ты пропустил if

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

«компилятор» = «гипотетический, но без чудес и чОрной магии, компилятор»

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

> пиши свой вариант кода с функциями foo bar baz

void f(x) { foo(x); bar(x); baz(x); }

и говори, как компилятор поймет, что ты пропустил if

x не используется в if вообще (т.е. никак не ограничен), что там понимать?

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

>>> В роли «мамой клянусь» - обычный if.

и говори, как компилятор поймет, что ты пропустил if

x не используется в if вообще (т.е. никак не ограничен), что там понимать?

стоит ли что-то обсуждать в таком стиле? мне кажется не стоит.

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от tailgunner

> А что «ага»? Такое использование сейчас невозможно, но я не вижу причин, по которым его нельзя реализовать

Ну, если ты не понимаешь, что нельзя собрать ELF/COFF/etc, прописав размер bss сегмента, на основании тех данных, что будут введены пользователем в запущеный на исполнение это же elf/coff, не имея на руках машины времени, то у меня для тебя плохие новости...

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


Да что ты?

http://www.linux.org.ru/jump-message.jsp?msgid=5034750&cid=5046164 :

а насчет маразма — меня интересует решение вот этой http://www.linux.org.ru/jump-message.jsp?msgid=4911022&cid=4912133 задачи


http://www.linux.org.ru/jump-message.jsp?msgid=5034750&cid=5046197 :

есть класс Array, инстансы которого создаются с длинной, определяемой по вводу от пользователя,но далее неизменно;



Как видим, лично я хотел самый обычный array :))

LamerOk ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

> вот уже несколько человек ждут от меня какого-то чуда, ну или думают, что я его щас поведаю :-)

Вовсе нет. Несколько человек совсем не ждут от тебя чуда, но им чертовски интересно, как ты будешь выкручиваться. ;)))

чуда нет


Кто б сомневался.))

присваивание из int в Int<0,15> кидает исключение;


Т.е. - райнтайм. ЧТД.

профит *только* в том, что забыть написать строку с if нам никто не помешает, а забыть написать строку с try помешает нормальный компилятор


А юмор в том, что описанная тобою фигня является enum'ом. Мои поздравления! :D

LamerOk ★★★★★ ()
Ответ на: комментарий от LamerOk

> Т.е. - райнтайм. ЧТД.

между нереалистичным «телепатическим шаблоном» и «рантаймом» есть куча промежуточных (и реалистичных!) способов использования типизации; но я устал пытаться обратить ваше внимание на эти спосообы, так что продолжу как-нить в другой раз

в конце концов, тема — ООП, и там есть что пообсуждать кроме этого

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от LamerOk

> Ну, если ты не понимаешь, что нельзя собрать ELF/COFF, прописав размер bss сегмента, на основании тех данных, что будут введены пользователем

Ну, если ты не понимаешь, что речь не об этом...

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

Да что ты?

http://www.linux.org.ru/jump-message.jsp?msgid=5034750&cid=5046164 :

И? Пройди по ссылке и увидь текст, начинающийся с: «Есть класс Array, инстансы которого создаются с длинной, определяемой по вводу от пользователя».

Как видим, лично я хотел самый обычный array :))

Не-а. По-моему, ты хотел просто повыпендриваться своей практичностью.

tailgunner ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.