Язык, Для чего, С чем.
Сперва мини история =)
С недавнего времени занялся изучение программированием, так как это будет в будущем моей профессией. Ну как вы знаете в учебных заведениях нифига не учат и берут только деньги, и студенты ( скажем большая часть ) говорю это, так как я сам на данный момент студент - сидят и играют всякие игры, просто тупое убивание времени. Я этого не понимал, но в скорее я осознал что я "дурак" что тоже сидел, играл игры и т.д. не занимаясь ничём полезным, не думал про будущее.
Скажем так : всё что происходит с человеком - виноват он сам.
Вот я "забыл" на эти игры, начал учится по своей буд. специальности. Сидел на форумах, искал в поисковых системах разную информацию, читал книги.
Я много раз замечал, что на форумах создают темы где спрашивают с чего начать, и почти на всех форумах одинаковые ответы, например ( учи С++ / С# или там Delphi а еще : учи то что тебе нравится ) ну а я подумал, как можно что то изучать, если не знаешь для чего и под что его можно использовать.
Вопрос :
Вот тут я хотел задать вопрос или даже несколько : какой язык и для чего используют, какие направления есть ( там для написание программ, для создание сайта и т.д. ) хотел бы узнать КЛАССИФИКАЦИЮ, НАПРАВЛЕНИЙ чтоб определиться какой язык выбрать ...
Заранее прошу прощение :
- русский у меня хромает - понемногу изучаю.
- если неверно сформулирован вопрос ( от него зависит ответ который я хочу получить, но надеюсь вы поймете что я хочу =) )
- если подобная тема была создана ( типа мне было лень искать, если я даже нашел, ответа того что я хотел - не увидел )
буду очень благодарен, если кто то уделит мне 5-10 мин. своего времени
для написание ответа.
П.С.
- в ходе написания ответа прошу не переходит на личное, типа "купи букварь" и т.д.
- если не знаешь ответ - проходи мимо, глупости не пиши.
Вероятно, точнее будет сказать - учебный. Захотел изучить ФП - бери Хаскель или Лисп. Захотел ООП - берёшь Смолталк. А в гибриде не поймешь где что. Потому гибриды представляют в основном практический интерес.
Так и я про то же.
А где вы натыкаетесь? Если ты командуешь объектами не думая, то где угодно получишь неизвестно что. В статике тоже есть виртуальные перегруженные методы, которые могут отличаться.
А разве не нужно сделать здесь интерфейс IPlavuchiyObject, реализующий метод Swim()?
Можно. Это будет тот самый "папа".
Ну так в том и фишка. Изучать можно без переключений на другие языки. Архитектура программы задается в ООП-стиле. "Микроменеджмент" можно выполнять в функциональном стиле - как хочешь так и пишешь код. В этом и сила гибридных языков.
Они могут отличаться внутренне, но выполняют вполне определенные вещи (для класса в котором эти абстракции введены), в противном случае это стало бы нарушением принципа подстановки.
Это не "папа". Интерфейсы не наследуются в обычном смысле (у них нечего наследовать - ни полей ни логики) - они реализуются. Интерфейс как правило несет семантику некоего контракта, реализуя интерфейс в классе мы говорим "этот класс теперь поддерживает такой-то способ работы с ним".
Это в теории. А на практике, если язык поддерживает несколько парадигм, то ты будешь использовать ту, к который привык, а на остальные плеваться. Если же выхода нет, то придётся вникать.
Если повникать в STL и Boost, то там можно найти много чего из ФП. Значит ли это что для изучения ФП хорошо подходит C++? Красота же - отрываться не надо.
Они будут выполнять "вполне определённые вещи", если ты в них это заложишь. Так же и в динамике.
Вообще, если отойти от этого спора, то моё мнение в том, что нужны языки с разной типизацией. На динамике строится прототип, который устраивает заказчика, ибо на это уйдёт времени во много раз меньше, чем если бы делали сразу в статике. Если есть время, то потом переписывается на статике, чтобы работало быстрее. Если времени нет, то он пользуется прототипом.
Так проблема не в полях и логике. Проблема в монолитности получаемой структуры, в зависимостях и дублировании.
Сколько гибридных языков с выводом типов ты попробовал? Парадигма ООП отлично уживается с ФП - они вообще разные задачи решают. ООП определяет свойства системы типов, а ФП - способ записи алгоритмов.
Идея ФП в иммутабельности данных и чистоте функций, если в этом ключе писать на C++ то вполне можно получить бонусы.
Создавать прототипы на Nemerle также быстро (если не быстрее) как создавать прототипы на Python.
Где там зависимость (от чего?) и дублирование (чего?).
Интерфейсы какраз призваны решать первую задачу - ликвидацию паразитных зависимостей (может быть стоит научиться ими пользоваться?).
То есть императивного программирования у вас нет?
Так я спрашивал не где бонусы, а где проще научиться.
Я понимаю, что ты в это веришь. Не буду тебя переубеждать.
Интерфейсы какраз призваны решать первую задачу - ликвидацию паразитных зависимостей (может быть стоит научиться ими пользоваться?).
Зависимость в том, что если класс мне надо перетащить в другой проект, то либо тащить за ним этот интерфейс, либо вычищать его из класса. При том, с интерфейсом ещё и какой-нибудь модуль потянется.
Но это маленькая проблема (и я об этом говорил) и потому вы на ней сосредоточились. Как будете со второй, которую я назвал более сложной?
За такие вопросы мне обычно модератор делает замечания в Общалке. Или даже редактируют сообщения. Поэтому не буду тебе отвечать в том же духе :)
Есть. Это когда в коде появляется ключевое слово mutable и всяческие циклы.
Так я спрашивал не где бонусы, а где проще научиться.
Согласен, в С++ сложнее, но тем не менее в нем ФП возможен и используется.
Я понимаю, что ты в это веришь. Не буду тебя переубеждать.
Мы в N1/N2 тем и занимаемся что прототипы создаем. ;)
Зависимость в том, что если класс мне надо перетащить в другой проект, то либо тащить за ним этот интерфейс, либо вычищать его из класса. При том, с интерфейсом ещё и какой-нибудь модуль потянется.
Интерфейсы как правило во внешних модулях лежат, у которых зависимости минимальные. Общие классы выносятся в общие же модули. В .NET все это делается тривиально (при том на уровне компании!): есть общие библиотеки, которые входят в десяток продуктов. Изменение исходников в таких бибиотеках приводит к пересборке всех продуктов.
Это какая?
Я тут подумал, что зависит от прототипа, который создаётся. Некоторые прототипы хорошо делать, например, на Дельфи. Зависит от конкретной задачи.
Вот и я про то же.
Если надо использовать готовые классы от разных производителей, то как им делать общий интерфейс? Решения есть, но многословные.
Вот и я про то же.
Так я еще и следствие из этого показал - изменение в общих библиотеках приводит к пересборке всех зависимых от них проектов (что дает нам дополнительные гарантии при рефакторинге).
У них как правило и интерфейс существенно отличается - что в .NET, что в Python-е :) Так или иначе придется делать свою обертку над ними.
Есть разница. Если один класс класс чужой, а второй - мой, то в статике у чужого класса обязательно должен быть подходящий мне интерфейс, чтобы я мог его реализовать в своём. В идеале, чужой должен наследоваться от кучи интерфейсов, в каждом из которых будет по одной функции, чтобы я мог выбрать то, что надо. В динамике я просто создам свой класс по подобию чужого.
Добавлено позже. И при том, мой класс даже не будет знать, что есть некий конкретный модуль, в котором лежит конкретный интерфейс. Нету лишней привязки к конкретике.
Ты не понимаешь предназначения интерфейсов.
Это в том случае, если производитель предоставил открытую иерархию и у тебя действительно есть причины следовать ей. Как правило разработки третьих лиц обертываются в собственные оболочки - это позволяет при необходимости заменить эти классы новыми: меньше зависимостей - лечге изменять.
Пример: экспорт неких наших данных в PDF формат.
1) находим библиотеку позволяющую работать с PDF,
2) объявляем интерфейс навроде IPdfReporter в котором будут метод(ы) экспорта,
3) пишем обертку к той библиотеке, реализующую этот интерфейс,
4) пользуемся для экспорта исключительно интерфейсом IPdfReporter,
5) в случае отказа от использования библиотеки и перехода на новую нам нужно просто заменить обертку на новую - код, пользующийся интерфейсом не заметит разницы
З.Ы. Либо вообще делаем нечто называющееся IReporter, одна из реализаций которой и будет в PDF отчеты писать.
Добавлено позже. И при том, мой класс даже не будет знать, что есть некий конкретный модуль, в котором лежит конкретный интерфейс. Нету лишней привязки к конкретике.
Начиная с некоторого размера исходного кода проектов выделять абстракции и разделять зависимости тебе ой как придется.
С какого размера? Назови приблизительный размер.
Многие программы могут быть сколь угодно большого размера, но быть просты как маленькие. И чтобы они такими были надо соблюдать несколько принципов, которые не зависят от интерфейсов, записанных вручную. Например, это "слабая связанность", "сильное зацепление", полиморфизм и т.д. Эти принципы не зависят от абстракций, записанных в файлах. Абстракции, которые нигде не записаны подходят лучше.
[QUOTE=hardcase]Ты не понимаешь предназначения интерфейсов.[/QUOTE]
Возможно. В чём отличие абстрактного класса (без полей и реализованных функций) в C++ от ваших интерфейсов? Я думаю ни в чём. Но может есть тонкости?
Так вот эти абстрактные классы я применял везде где мог в C++. И применяю, ибо в языках со статической типизацией это удобно. В языках типа Python их используют только те, кто начинал с языков со статической типизацией. По привычке.
Думаю, мы дошли до догм, поэтому дальше спорить на эту тему нет смысла.
Вроде бы где-то на РСДН некий Влад утверждал, что для этого нужен год?
Есть ли какие-нибудь фундаментальные материалы для Nemerle, что-нибудь типа стандарта С++?
Цифра с потолка - 5-10 kloc. В каждом случае свой критерий (на самом деле это нужно делать сразу).
Это ты сейчас кого процитировал? :D
Программа не может быть сколь угодно большого размера с константной "функцией сложности" - её в любом случае будет сложно читать из-за возрастания размера.
Так вот идею "слабой связности" и "сильного зацепления" позволяют реализовать интерфейсы (они по сути для этого и нужны), абстракции которые явно записаны в коде - документированы. Более того, мы можем формально проверить соответствие им, чем отчасти и занимается компилятор. Абстракции, которые возможно контролировать на этапе компиляции позволяют контролировать сложность софта.
В С++ интерфейсы реализуются посредством чистых абстрактных классов это возможно потому что в С++ есть множественное наследование. Интерфейс не содержит каких либо полей и реализации методов.
Только применять их надо не везде где можно, а там - где нужно.
Где тут догмы? Это факт - строгая статическая типизация в правильных языках удобна, совсем не мешает, а наоборот - помогает работать и контролировать сложность разрабатываемой системы. Мой поинт тут в том, что кое кто из нас просто не умеет "готовить" систему типов.
Если знаешь C#, то ты уже можешь использовать Nemerle.
Год нужен для того чтобы с нуля подойти к идее метапрограммирования на типобезопасных макросах.
Есть цикл статей того же Влада (с нуля это "Язык Nemerle"), посвященных Nemerle. Ну и моя аватара :)
Вот именно, что не с 5-10 kloc, а с гораздо меньшего размера. И тот ООП, что есть в Python, способствует. Скорее всего, в Ruby ещё лучше с этим дело, если верить рекламкам.
И в общем, я согласен, что размер кода программ мне надо уменьшать. Потому я и выбираю соответствующие языки. Не совсем понимаю твоё ехидство, но бывает.
Год или более назад я купил отличную книжонку про UML Крейга Лармана, где он пишет о шаблонах GRASP. Вот те, которые я упомянул, запомнил и стараюсь применять. Ну, ещё "информационного эксперта".
Рекомендую. Хорошая книжка.
И не надо говорить, что Java может каждый раз компилироваться в идеальный код, рассчитанный на конкретное железо. То же могут и компиляторы си. Код придётся перекомпилировать вручную, но мы то говорим о скорости :)
А я буду говорить. Потому что преимущества динамической компиляции в той же яве не только в том, что она компилируется на машине с конкретным процессором / архитектурой, и не ограничена в наборе инструкций под i386 / i586, но и в том, что динамическая компиляция в долго работающих серверных приложениях позволяет оптимизировать код по мере того, как изменяется профиль нагрузки. Это важно.
Т.е. суть JIT-а в том, что когда определенные методы вызываются очень часто, то они компилируются в машинный код и держаться какое-то время в кеше виртмашины. Это знают все.
А вот что знают не все, так это то, что JVM, например, уверен что и CLR, умеет делать де-оптимизацию кода. Т.е. если по прошествии некоторого времени профиль нагрузки приложения изменился, и теперь методы, которые раньше вызывались очень часто, вызываются достаточно редко, а часто вызываются другие методы - то JVM выкинет скомпилированный код для первой группы методов (если память в кеше машинного кода поджимает), и вместо этого скомпилируют те метода, которые стали вызываться часто в последнее время.
Спасибо за комментарий. Познавательно.
Но код на си может тупо содержать все методы оптимально скомпилированными. Для этого ему может хватить той памяти, которую освободит виртуальная машина :)
Зависит от ситуации, конечно. Пока могу согласиться, что был приведён пример гибкости JVM. Но оно играет роль при сравнении с другими виртуальными машинами, а не с кодом на си.
А теперь покажи мне вебсервисы на Си, механизмы доступа к данным на Си (с автоматическим маппингом столбцов на поля), механизмы автоматической сериализации в XML - кароче все то, что можно охарактеризовать как плоды "метапрограммирования".
Это зачем? Можешь подробнее расписать как влияние типобезопасности на скорость связано со всем этим?
Ну так .NET и JVM являсь типобезопасными предоставляют еще уйму фичей всяческих, коих в Си просто невозможно реализовать.
Вполне допускаю что так и есть. Тебе виднее.
Надо написать на С интерпретатор Лиспа ;)