LINUX.ORG.RU

Зачем нужны динамические языки?


0

0

Собственно не пойму. Вроде обещают более быструю разработку, но за счет чего? За счет того, что не надо писать тип при объявлении переменной? Так это ведь глупость, никакой скорости разработки это не добавит. Естественно, такие языки можно использовать только для прототипирования, но не проще ли сразу использовать язык, который обеспечит и скорость разработки и скорость выполнения, тем более, что динамический язык принципиально нельзя ускорить (имеется ввиду компилятор)? (я имею ввиду современные языки с выводом типов)

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

> Насчет букв -- скажи в консоли dd --help и подумай, удобно ли будет задавать столько параметров позиционно. А если задавать их включевую, то статический язык их еще и бесплатно проверит.

Чем тебе помогут пятьдесят типизированных параметров при последующем чтении кода?

runDd(iFileParam, oFileParam, iBufSize, oBufSize, iSync, oSync, convertType, status);

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

> int res=DD::run(If("asdf")+Of("qwer")+NOXFER);
> если не ошибаюсь, можно писать If вместо DD::If


Я там вообще какую-то фигню сморозил, так что лучше на неё не отвечать.
Спать пора...

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

> Я там вообще какую-то фигню сморозил, так что лучше на неё не отвечать.

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

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

> Все же выяснилось, что плюсы эту ошибку ловят... это уже хорошо.

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

> Насчет букв -- скажи в консоли dd --help и подумай, удобно ли будет задавать столько параметров позиционно.

Конечно неудобно. И именно в динамических языках была развита культура именованных аргументов. В чём состоит твой аргумент? В динамических языках возникают ошибки типа -- передан хеш параметров с недопустимым ключом. Или значение такого-то значения для такого-то ключа недопустимо. Так совершенно элементарным образом отлавливаются ошибки связанные с опечатками в именах именованных аргументов.

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

Я знаю, что типизация аргументов что-то отлавливает во время компиляции. Знаю также, насколько она намертво цементирует код и не позволяет сделать ни шага влево или вправо. Нужны примеры? Привести их здесь сложно. Зато просто рассказать рецепт самостоятельного получения примера в домашних условиях -- напиши веб приложение на django или RubyOnRails и захоти добавить какую-нибудь новую функцуциональность к существующему модулю. Картина мира может резко прояснится. Или попробуй повторить django или RubyOnRails на С++. Просто тут крутые все из себя пргограммисты, дошли до некоторого уже уровня и 20 строчных примеров им недостаточно. Нужен опыт разработки разнотипного софта: 1) десктоп приложений 2) веб приложений 3) прототипирование архитектуры чего-либо на функциональном языке 4) скриптиков для администрирования 5) .. Каждый вспоминает весь свой опыт и делает какие-то выводы. Вспоминает, что его мучало, а что радовало в разработке. Очень даже понимаю, что человек, который всю жизнь писал утилитки для линукса на Си будет утверждать, что он жить не может без типизации аргументов, и кто говорит, что она вредна, ничего не понимает. Как вообще без типизации жить, если она служила ему верой и правдой столько времени? Ответ простой - сменить класс задач и/или отношение к ним. Нужно захотеть писать быстро и много, и не писать ни строчки кода для машины, нужно очень сильно захотеть писать такой код, где высока плотность мысли, такая же как в естественном языке или выше. Ни строки в угоду машинному уровню. Ни строки повторений. Пусть язык и машина прогибаются под тебя, а не наоборот. Нужно этого реально захотеть и тогда типизация пойдёт лесом.

Кстати в Ruby, в отличие от Perl, строгая типизация, хоть и динамическая. Какие-то ограничения всё таки нужны. Но включение в сигнатуру типов - это ограничение-прогиб под архитектуру компьютера, а не полезная фича для человека. Такое моё ИМХО

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

> Знаю также, насколько она намертво цементирует код и не позволяет сделать ни шага влево или вправо.

Ты похоже современную типизацию не знаешь.

> И именно в динамических языках была развита культура именованных аргументов.

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

> Нужны примеры? Привести их здесь сложно.

Именно в этом и смысл дискуссии. Сказать "попробуй сам, поймешь" гораздо проще, чем указать пример из 20 строк, который будет неудобен на каком-то типе языков.

> Кстати в Ruby, в отличие от Perl, строгая типизация, хоть и динамическая.

Например, где руби строже, чем перл?

> Каждый вспоминает весь свой опыт и делает какие-то выводы. Вспоминает, что его мучало, а что радовало в разработке.

Проблема в том, что после этого происходит неправильное соотнесение "меня мучило это в языке Х со статикой --- значит это будет мучить во всех языках со статикой".

Список приятных фич ruby -- welcome. Но учти, что их принадлежность динамической типизации я могу оспаривать.

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

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

Солидарен.

> Нужно этого реально захотеть и тогда типизация пойдёт лесом.

Тогда ты откроешь type inference и возможно создашь собственный язык.

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

> > А вот и не ГЫ-ГЫ-ГЫ ... зашаривание локальных переменных между двумя замыканиями с целью зашаривания и обмена данными - это классика в динамическом программировании.

> гы-гы-гы

Нет, снова не ГЫ-ГЫ-ГЫ.

> boost::shared_ptr<Foo> ptr = new Foo(.....); и дальше спокойно шаришь ptr между двумя замыканиями после выхода из функции

> идея сохранять стэковый фрейм -- это spagetty stack и неэффективно

О сложности реализации и эффективности - это отдельный разговор. А вот полезно ли? Оказывается, иногда полезно.

> З.Ы. жаль в жцц 4.4 еще замыканий нет, а то бы дал рабочий пример в 10 строк.

Во первых, нужно сначала дождаться выхода компилятора. Я смогу написать кучу нерабочего кода в 10 строк, который толпы программистов на С++ будут писать и считать рабочим - вот ведь в чём ещё прикол.

Необходимость локальные переменные, которые мы хотим зашарить, оборачивать в shared_ptr<Foo> мне не нравится. Языки отличаются друг от друга не тем, что на них можно сделать (этим они практически не отличаются, так как все они квазитьюрингполны), а выразительностью. Каждая лишняя обертка дорого стоит. Это нужно вопринимать как крепкий прогиб под железячку. Собственно это еще одна причина, которую явно формулируют те, кто слез с С++ и Java -- надоело писать обертки и плодить классы и типы ради каждого плевка.

Вспомним ради чего всё это делается? Хотим прямо в выражениях создавать анонимные функции - то есть хотим видеть код прямо рядом с тем месом, где он нужен, не оформляя всякую мелочь в виде функции или функторов, и не раздавая этой мелочи имён (- не заслужили). Но если при этом я должен заботится о том, чтобы переменную типа int оборачивать shared_ptr'ом, а значит внутри лямбды использовать разименование указателя, то как-то сильно начинает страдать читаемость кода и увеличиваться напряжение мозга программистов, которые читают код друг друга. К тому же я заранее могу не догадаться, что у меня будет использоваться эта локальная переменная для расшаривания. И буду ее использовать обычно. А потом вдруг окажется, что должен создавать ее как new, и везде использовать с *. А может лучше использовать старые добрые всем уже известные функторы?

То, что на С++ возможно всё, я не сомневаюсь. Я сомневаюсь в том, что добавляя к нему новые динамичные фишки, мы получим повышение выразительности и практической используемости языка.

Вспомнил, что основной пример того, когда нескольким лямбдам требуется зашарить один и тот же набор переменных, -- это создание ряда _именованных_ функций, имена которых и значения зашаренных переменных зависят от опций, переданных мета-методу. См. например http://rails.vsevteme.ru/posts/show?id=6407 (часть "10 кю. Пишем правильно"). А это уже неподьёмно стандартными средствами. Попробуйте переписать на С+ хотя бы схематично, опуская принципиально невозможные вещи, код на Ruby, предоставленный в этой части, используя эту технику с shared_ptr. Сравните размер кода на С++ и исходного кода на Ruby. Честно сравните внятность и читаемость.

Ещё по сабжу написано там же в http://rails.vsevteme.ru/posts/show?id=6009

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

> Например, где руби строже, чем перл? 

# Perl
$a = "1.5"
# тип скаляр - это все что угодно, зависит от контекста использования.
$a + 1 # => 2.5
$a . 1 # => 1.51

Переменная $a просто не имеет типа.

В Ruby любой объект имеет совершенно конкретный тип.
a.class вернет тебе Fixnum либо Float либо String либо Array, ...

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

1.5 + "abc" # String can't be coerced into Float (TypeError)

greck:~$ perl -e 'print( 1.56 . 1 . "\n" )'
1.561
greck:~$ perl -e 'print( 1.56 . "abc\n" )'
1.56abc
greck:~$ perl -e 'print( "1.56" + 1 . "\n" )'
2.56
greck:~$ ruby -e 'print( "1.56" + 1 )'
-e:1:in `+': can't convert Fixnum into String (TypeError)
	from -e:1
greck:~$ ruby -e 'print( 1.56 + "abc\n" )'
-e:1:in `+': String can't be coerced into Float (TypeError)
	from -e:1
greck:~$

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

> В общем, нефиг в рантайме делать то, что могут сделать перловые скрипты во время компиляции.

ох хо хох!

А как же гомогенность ПО? А как же (патчи к сгенеренных автоматом файлам/постоянная доделка скрипта-генератора), чего не может не быть при таком подходе если речь живет о реальном программировании?

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

>> Сходу что в голову приходит - в лисповых ОО СУБД можно в рантайме поменять определение класса, и все готовые объекты лениво поменяются под новое определение. Вот тут, подозреваю, это во всю используется: http://franz.com/products/allegrocache/

> Че-то мне не понятно, как лениво менять все объекты без жутких тормозов. Ведь это надо вставлять проверку "а не поменялось ли определение класса" на каждый вызов метода этого объекта, или как?

Нет, такие проверки не вставляются. Все работает и без проверок. В динамических языках у классов нет строго заданного API -- не фиксированны ни instance-variables, ни methods, ни class method -- в общем, ничего. Единственное, что определяет класс -- это его имя. Смена API класса в рантайме не повод для того, чтобы что-то перестало работать. Это совсем другой мир.

Загрузка классов и обращения к базам данных (SHOW FIELDS FROM tablename) делается лишь в самом начале, во время "разогрева" приложения, когда оно инициализирует классы (которые кстати инициализируются часто по мере надобности, засчет того, что _переопределяется_ метод constant_missing, в который уже пишут не бросание эксепшена, а поиск библиотечного файла с соответствующим именем равным запрашиваемому классу для того, чтобы его загрузить, если файл не найден в стандартных директориях или файл найден, но почле его загрузки класса не появилось -- вот тогда уже и бросается эксепшен). Да, если поменялась модель данных в базе данных, придётся перезагрузить веб приложение, чтобы оно почувствовало эти изменения. Но тут уж извините, иначе нельзя.

Имплементация проста. Основная идея, с которой начинали - пусть объекты на внутреннем уровне это хеши, ключи хеша - суть instance-переменные. Функции лежат отдельно от объекта и у них (на уровне внутренней реализация) первый аргумент есть ссылка на объект. Да, работать с хешом дороже, чем напрямую обращаться к переменным, используя известное смещение относительно начала объекта. Но этим готовы платить за динамичность.

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

>>Создать класс в рантайме. С именами полей, введенными пользователем.

> о, вот это уже интересней. а зачем это может быть нужно?

см. ORM, например ActiveRecord (http://ar.rubyonrails.org/), DataMapper (http://datamapper.org/doku.php?id=getting_started_with_datamapper).

При инициализации класса сначала идет обращение к базе данных SHOW FIELDS FROM tablename, а потом создаются setters & getters методы. Большинство современных фреймворков для веб-разработки используют это.

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

> Тогда ты откроешь type inference и возможно создашь собственный язык.

Я знаком достаточно хорошо с шаблонами С++ (уже не возбуждает) и с красивейшей системой типов в Haskell (наслаждаюсь иногда, читая и слушая академиков (например, слушал Непейводу Н.Н. о связи типов в Хаскел с системой аксиом Гильберта и интуисткой логикой), но не использую, и сам рассказываю про неё студентам, когда настроение лирическое).

Рекомендую по умолчанию предполагать, что собеседник всё понял, и не писать ответов типа "разборки ты наши не понял, елки палки.", "тогда ты откроешь для себя ..". А если пишешь, то снабжай аргументами или ссылкой.

С++ и Haskell открыл для себя давно. И не закрывал их. Может есть что-то лучше, чем type inference в Haskell? Тогда ссылку дай.

Если аргументируешь, возможно пересмотрю и С++ и Haskell.

Участвовал в проектах, где писали просто, без наворотов, не сильно переживали, когда код был не general; не сильно переживали, когда случалось сделать copy & paste (неприятно было, но терпели). Знаком был с проектами, где пытались использовать все навороты С++ (без злого умысла, из лучших побуждений) (практически все классы были шаблонами, использовалась вся боевая мощь С++: функторы, касты и птры стандартные и самописные пестрели повсюду - как итого - не все компиляторы справлялись и было найдена куча ошибок в компиляторах, которые приходилось хитро обходить, и было сломано много голов программистов). Проекты второго типа оставили особенно тяжкое впечатление.

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

На остальные твои темы я постепенно отвечу.

> Рекомендую по умолчанию предполагать, что собеседник всё понял, и не писать ответов типа "разборки ты наши не понял, елки палки.", "тогда ты откроешь для себя ..".

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

> А если пишешь, то снабжай аргументами или ссылкой.

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

Если бы ты привел 20 строк кода на хаскеле я бы тебя воспринимал по-другому.

В любом случае, поговорить с тобой будет интересно.

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

> А как же гомогенность ПО? А как же (патчи к сгенеренных автоматом файлам/постоянная доделка скрипта-генератора), чего не может не быть при таком подходе если речь живет о реальном программировании?

Так и не понял, что ты тут нашел отрицательного, раскрой тему. Гомогенность ПО -- в принципе может и хорошо, но практически -- мейкфайлы там например...

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

> не сильно переживали, когда случалось сделать copy & paste (неприятно было, но терпели).

вот интересно, когда это на плюсах требуется копипаст?

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

> (часть "10 кю. Пишем правильно"). А это уже неподьёмно стандартными средствами. Попробуйте переписать на С+ хотя бы схематично, опуская принципиально невозможные вещи, код на Ruby, предоставленный в этой части, используя эту технику с shared_ptr. Сравните размер кода на С++ и исходного кода на Ruby. Честно сравните внятность и читаемость.

ты просишь ORM для плюсов, я правильно понял? и еще желательно задачу поточнее сформулировать, что требуется.

варианты могут быть: 1. юзать внешнюю прогу для рефлексии 2. не юзать, но тогда названия полей класса я не смогу узнать, и полями класса будут наследники моего класса Object (типы будут обрабатывать правильно)

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

-- :]
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}

import Data.Int

class MyFoo a where       foo :: a

-- some simple non-plymorphic instances for MyFoo
instance MyFoo Int  where foo = 3
instance MyFoo Char where foo = 'z'

-- user-crafted polymorphic typeclass:
class MyBar a where               bar :: a

-- put anything to MyBar!
instance MyBar Double where       bar = 1.2
-- let it be 'const T * ' analogue: constrained polymorphic subtype
-- (could be in MyFoo tho)
instance (Num a) => MyBar a where bar = 4

-- add MyBar as an instance of MyFoo
instance (MyBar a) => MyFoo a where
    foo = bar

--
--

main = do print (foo :: Int)    -- MyFoo Int
          print (foo :: Char)   -- MyFoo Char
          print (foo :: Int64)  -- MyBar (Num a)
          print (foo :: Double) -- MyBar derivative

{-
Справедливсти ради надо отметить, что нельзя определить реализацию _сразу_ для 2х разных полиморфных подтипов (например, всунуть в MyBar еще и Monoid a). Так как они открыты - гад юзер может всунуть туда всё, что захочет и получит неоднозначность: из какого instance брать реализацию?
Собственно у нас почти это и происходит в пересечении у нас { a | Num a} и {Int, Double}, но Int - более кАнктерный и ч0кей, чем Num a, по-этому всё АднАзначнА (прям как в C++ ;], хоть и с расширениями).

Особо интересен случай, когда класс типов полиморфен сразу по нескольким параметрам (multiparameter typeclass) и нужно указать зависимость типов между собой (пример - Regex из regex-base: http://hackage.haskell.org/packages/archive/regex-base/0.93.1/doc/html/Text-Reg
ex-Base-RegexLike.html#t%3ARegexOptions).

Насколько я знаю в C++0x есть(?) только concepts, которые таких зависимостей не могут указывать :p

http://en.wikibooks.org/wiki/Haskell/Advanced_type_classes
-}

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

> А вот мне чисто в теории интересно, можно ли в Хаскеле сделать так, чтобы во время
> компиляции открывался какой-то сторонний файл и что-нибудь в него можно было

> записать/прочитать.


> Или (самое тупое), чтобы посреди файла возникал на консоли запрос к пользователю

> "введите следующий оператор, который мы вкомпилируем в наш файл"

Так как на стадии компиляции можно вызывать полноценный компилятор haskell - можно (не 1й раз говорят! ;]).

> В лиспе и m4 это возможно. Кто скажет, что это не нужно - тот лох.

[snip]

пример хороший :]

> И ещё два вопроса по Хаскелю.


> 1. Можно ли определить в Хаскеле тип "строка или чётное число"?


Можно. (допустим, Even уже есть)

data EvenOrString = EN Even | S String
Другое дело - какие приличные операции над этим типом определять? :]

> 2. Если там есть классы, то можно ли изменить класс сущности? Т.е., вчера объект был

> класса "куколка", а с сегодняшнего дня пусть у него будет класс "бабочка". При этом, чтобы он сохранил свою идентичность.


Вчера? Идентичность?

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

Кстати задачу про параметры dd на C++ я бы решил заведя отдельный класс для генерации коммандной строки для него, а потом вызвав что-то вроде:

int res = run_dd (default_dd_config.clone().set_bs(10).set_count(100).set_out("/dev/null");

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

> Рекомендую по умолчанию предполагать, что собеседник всё понял

В 99% случаев это предположение будет неверным, так что рекомендация нехорошая.

> см. ORM

Я, конечно, не знаю жабу нифига, но, как я слышал, ORM там есть. Как и рефлекшн. При этом жабка - опять-таки, как я слышал - статически типизирована.

> При инициализации класса сначала идет обращение к базе данных SHOW FIELDS FROM tablename, а потом создаются setters & getters методы. Большинство современных фреймворков для веб-разработки используют это.

Вполне можно делать при компиляции.

> А как же гомогенность ПО?

Я не видел пока ни одного проекта, который был бы полностью гомогенным. Всегда было что-то ещё - как минимум, виндовые bat-файлы (на которые я могу матюкаться очень долго, но сути дела это не меняет). Выгод от гомогенности я не понимаю вообще. Возьми, например, геймдев - попробуй заставить скриптописателей использовать плюсы, или программеров физики использовать питон.

Хотя в одном я соглашусь - перловый скрипт - не лучший вариант. Лучше сделать маленький (E)DSL.

> Знаю также, насколько она намертво цементирует код и не позволяет сделать ни шага влево или вправо.

Насколько я могу понять из твоих постов, писал ты только на плюсах. Там, действительно, наблюдаются проблемы (хотя и не такие фатальные, как ты здесь пишешь). Может, ты и знаком с type inference, но явно не пользовался.

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

C - плохой пример, там можно привести почти что угодно почти к чему угодно, и, более того, подобное приведение повсеместно практикуется. В плюсах тоже можно, но настолько хорошим тоном уже не считается.

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

Красиво говоришь. Именно поэтому я стараюсь использовать хаскель почаще.

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

Поэтому пусть сигнатура вообще автоматически выводится.

> С техникой насильного введения новых ненужных (дублирующих уже существующие, но "другие") типов специально для отлавливания ошибок типизации я знаком.

> Букв приходится писать больше. Ошибки такого сорта предпочитаю находить другими способами.

В том и фишка, что это "техника" в плюсах, и абсолютно нормальное состояние в хаскеле. И новых букв почти нет.

> Одно дело copied, и совсем другое дело, когда две разные лямбда реально шарят одну и туже локальную x переменную после того, как вычисление функции вообще закончилось.

Блин. Как я вообще купился, ведь знал же, что замыкания без сборщика мусора невозможны.

> Как только мы делаем это смешение, сразу получаем необходимость сборщика мусора.

При чём тут сабж? В современных статических языках есть сборщик мусора. В питоне его, AFAIK, до сих пор по-нормальному нет.

> ООП,

Олег Киселёв сделал ООП на почти стандартном Хаскеле.

> рефлексии

Data.Typeable, Data.Data - куча рефлексии в том же Хаскеле.

> отсутствия типов в сигнатурах функций и объявлениях переменных

Type inference.

> Agile Development она не помогает, а мешает.

Ровно наоборот.

> Если кто-то в Ruby хочет добавить метод sum ко ВСЕМ контейнерам

Если не ошибаюсь, Scala это умеет. С сохранением статической типизации.

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

> Если там есть классы, то можно ли изменить класс сущности?

В Хаскеле нет классов сущностей, есть классы типов.

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

> В современных статических языках есть сборщик мусора. В питоне его, AFAIK, до сих пор по-нормальному нет.

Мусор убирается, циклические ссылки разруливаютс - что не нормально?

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

> Да, если поменялась модель данных в базе данных, придётся перезагрузить веб приложение, чтобы оно почувствовало эти изменения. Но тут уж извините, иначе нельзя.

Это в динамическом языке иначе нельзя. В статическом - перегенерировал часть, инкапсулирующую взаимодействие с БД, а дальше компилятор укажет места, которые нужно править из-за несовместимости изменений. А в динамическом языке придется молиться на то, что тесты обеспечивают 100% покрытия.

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

>> Да, если поменялась модель данных в базе данных, придётся перезагрузить веб приложение, чтобы оно почувствовало эти изменения. Но тут уж извините, иначе нельзя.
> Это в динамическом языке иначе нельзя. В статическом - перегенерировал часть, инкапсулирующую взаимодействие с БД, а дальше компилятор укажет места, которые нужно править из-за несовместимости изменений. А в динамическом языке придется молиться на то, что тесты обеспечивают 100% покрытия.


С чего это? Ты применяешь к динамическому языку сразу все возможные ошибки и тем самым ставишь его в проигрышное положение.
В данном случае ты для статического языка явно указал, что взаимодействие с БД выделено в отдельный модуль, а для динамического размазал работу с бд по всему коду ровным слоем (иначе зачем тогда 100% покрытие?).

Кстати, база --- как раз место, где статика очень слабо помогает. Переименовал одну таблицу --- и всё, никакой стаитческий компилятор тебе не укажет на все запросы, где она используется. А уж с именами полей в запросах вообще страшно выходит.

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

> И именно в динамических языках была развита культура именованных аргументов.

Стырено из Ады, ЕМНИП...

> В динамических языках возникают ошибки типа -- передан хеш параметров с недопустимым ключом. Или значение такого-то значения для такого-то ключа недопустимо.

...только Ада умела ловить такие ошибки на этапе компиляции %)

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

> для динамического размазал работу с бд по всему коду ровным слоем

Нет, с чего ты взял?

> (иначе зачем тогда 100% покрытие?).

Модуль работы с БД предоставляет интерфейсы, которые зависят от схемы БД. Все модули, которые напрямую используют эти интерфейсы, должны быть покрыты 100%. Если эти модули, в свою очередь, предоставляют другим интерфейсы, зависимые по типам от схемы БД... эффект домино.

> Переименовал одну таблицу --- и всё, никакой стаитческий компилятор тебе не укажет на все запросы

Чтобы долго не спорить, скажу - для динамического языка ситуация ничуть не лучше.

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

>> А как же гомогенность ПО? А как же (патчи к сгенеренных автоматом файлам/постоянная доделка скрипта-генератора), чего не может не быть при таком подходе если речь живет о реальном программировании?

> Так и не понял, что ты тут нашел отрицательного, раскрой тему. Гомогенность ПО -- в принципе может и хорошо, но практически -- мейкфайлы там например...


В Ruby есть Rakefiles, которые пишутся на ... Ruby! Хорошо ли это? Да, это очень удобно. За счёт того, что Ruby может выступать в роли макроязыка, на нем пишется не только сам код, но и (примеры из rails):
1) конфиг маршрутизации (config/routes.rb)
2) конфиг самого приложения (config/environment.rb)
2) Rakefile
3) описания модели данных (модели и отношения one-to-one, one-to_many, ...)
4) валидации моделей данных и разные фильтры before_save, after_create, ... (они могли бы писаться еще на SQL, как триггеры и хранимые процедуры)
5) язык шаблонов для генерации HTML (см. haml, erb)
6) ...

Чем больше языков вы используете в своем проекте тем:
1) труднее найти новых программистов, которые на нужном уровне знают все используемые языки
2) больше проблем с совместимостью частей при переходе на новые версии и портировании
3) больше проблем с интеграцией разнородных частей и обеспечения реюза между этими частями

Гомогенность ПО -- в принципе хорошо, и практически к ней можно приближаться довольно успешно. - И это еще один аргумент по сабжу. На Си++ не получается сохранять гомогенность проекта, а на динамических языках - получается.

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

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

Программист, знающий меньше 10 языков - не программист, а обезьянка.

Знающий 20 - осваивавает любой.

> больше проблем с интеграцией разнородных частей и обеспечения реюза между этими частями

С чего бы? Те же траблы, что и в гомогенной среде.

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

>> Да, если поменялась модель данных в базе данных, придётся перезагрузить веб приложение, чтобы оно почувствовало эти изменения. Но тут уж извините, иначе нельзя.

> Это в динамическом языке иначе нельзя. В статическом - перегенерировал часть, инкапсулирующую взаимодействие с БД, а дальше компилятор укажет места, которые нужно править из-за несовместимости изменений. А в динамическом языке придется молиться на то, что тесты обеспечивают 100% покрытия.

Я написал "перезапустить", имея в виду серверное приложение. Перезапускать точно придётся, и как Вы еще отметили -- перекомпилировать. Напомню, что _перекомпилировать_ в динамических языках точно не придется, потому что это вообще никогда не делается. Еще раз: после смены модели данных _нужно_ перегружать серверное приложение, если это не rails в development конфигурации -- там он перегружает классы моделей сам при каждом запросе и отсекает эти изменения на лету, но в production это, конечно же, отключают, так как performance. Также отсекается дата изменения файлов классов моделей и HTML шаблонов и они тоже перегружаются на лету.

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

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

> Мусор убирается, циклические ссылки разруливаютс - что не нормально?

По дефолту разруливаются?

AFAIK там до сих пор всё основано на подсчёте ссылок. А это - один из самых тормознутых методов.

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

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

Не путаем интерпретируемость и динамическую типизацию.

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

>> Мусор убирается, циклические ссылки разруливаютс - что не нормально?

> По дефолту разруливаются?

Да, со времен 2.0

> AFAIK там до сих пор всё основано на подсчёте ссылок.

Да.

> А это - один из самых тормознутых методов.

На эту тему есть разные мнения... о нормальности это ничего не говорит. Копирующие multi-generational сборщики еще не все мозги зохавали :)

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

>> Или (самое тупое), чтобы посреди файла возникал на консоли запрос к пользователю
>> "введите следующий оператор, который мы вкомпилируем в наш файл"

>Так как на стадии компиляции можно вызывать полноценный компилятор haskell - можно (не 1й раз говорят! ;]).


Спасибо. На самом деле, это было не совсем очевидно. Т.к. полноценный компилятор не обязательно может делать произвольные действия. Вот когда говорят "во время компиляции можно вызвать компилятор, скомпилировать что-то, вызвать рантайм, выполнить и подставить результат выполнения в компилируемую программу", то это - уже однозначный ответ. По правде говоря, я так и не понял до сих пор, можно ли это сделать в Хаскеле. В лиспе и m4 можно, в С - нельзя (хотя #include con это прикольно, но где я могу прочитать сообщение "введите следующий оператор").

Кстати, да. Я хочу пример на Хаскеле, который пишет в консоль слова "введите следующее определение", запрашивает его и вкомпилирует в программу.

Пример на лиспе:

; файл ask-user-for-a-function.lisp:
(defmacro ask-user-for-a-function () (format t "Ну и?") (read))

(ask-user-for-a-function)
; eof

; в консоли лиспа:
#(compile-file "ask-user-for-a-function.lisp")
Ну и? <вводим (defun Хай! () "Привет!")>
#(load *) ; грузим то, что мы откомпилировали
#(Хай!)
"Привет!"

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

> data EvenOrString = EN Even | S String

> Другое дело - какие приличные операции над этим типом определять? :]


В лиспе это делается так:

(deftype even-or-string ()
`(or (and integer (satisfies evenp)) string))

При этом:

(typep 4 'even-or-string) ; принадлежит типу?
возвращает t (истина)

(typeof 4) ; какого типа 4?
возвращает что-нибудь вроде
(INTEGER 0 536870911)

(subtypep 'string 'even-or-string) ; является подтипом?
возвращает "да"

(subtypep 'integer 'even-or-string) ; является подтипом?
возвращает "нет", а есть ещё вариант ответа "не знаю"

(coerce 3 'even-or-string) ; привести 3 к типу
порождает исключение

(coerce 4 'even-or-string) ; привести 4 к типу
возвращает 4

Вот, соответственно, и набор операций над новым типом (если я ничего не забыл). Как видим, этот тип несколько виртуален. Т.е., не существует сущностей такого типа.

Я ничего не утверждаю насчёт того, круче ли это, чем Хаскель.
Но вот просто это так. И всё это (определение и, что самое главное, переопределение новых типов) можно делать в рантайме.

Соответственно, последний вопрос про Хаскель - можно ли переопределить тип в рантайме. Предугадываю отрицательный ответ...

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

http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_7-2.html

Честно скажу, что я очень редко пользуюсь deftype и ещё ни разу не пользовался change-class. Кроме того, я вообще не фанат CLOS, хотя со временем я всё же к нему привык и вынужден признать, что он весьма гибкий (и, соответственно, довольно тормозной и громоздкий при написании определений классов и методов). Чего не хватает лиспу - это возможности зацементировать те или иные классы, чтобы выиграть скорость за гибкость там, где гибкость не нужна. Однако, мне кажется, что проще зацементировать, чем добавить гибкости там, где её изначально нет.

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

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

> Программист, знающий меньше 10 языков - не программист, а обезьянка.


я был бы помягче и построже в суждениях и придерживался бы классической логики. Начнем с того, что "Программист, .. -- не программист, а ...." не может быть true.
А именно, я бы сказал так: "Очень плохо, когда программист хорошо значет только один язык программирования, и хорошо, когда он знает хотя бы три концептуально разных языка программирования"

> Знающий 20 - осваивавает любой.


Да, он крут. И видимо чем-то еще болен. Например неудержимым фанатизмом.

>> больше проблем с интеграцией разнородных частей и обеспечения реюза между этими частями


> С чего бы? Те же траблы, что и в гомогенной среде.


Обращаю внимание на то, что в гомогенной среде нет разнородных частей, поэтому с ними не могут быть траблы. Здесь придраться не к чему. Это злостный и дерзкий ЛОР, я пишу с осторожностью, но тем не менее, все равно с чем то спорят - Лучше ответьте по сабжу развернуто.

Примеры: cм. случайный http://pastie.org/pastes/368575. Обратите внимание как в Rakefile используется
1) require 'active_record/fixtures -- подключение библиотеки на Ruby
2) сам Ruby - разные методы для рабты со строками, файлами, массивами, .. которые хорошо известны программисту, так как он их использует в обычном коде.

Попробуйте задействовать в Makefile функции для работы со строками и контейнерами, которые Вы написали в одной из своих C++ библиотек. Это в принципе невозможно. Отмазки типа "а это и не нужно" не примаются. Практика огромного количества людей показала, что когда есть возможность использоваться стандартной библиотекой языка в конфигах, *akefiles, .., этой возможностью начинают пользоваться с пользой.




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

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

> Не путаем интерпретируемость и динамическую типизацию.

Извини, ставлю в игнор.

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

>> AFAIK там до сих пор всё основано на подсчёте ссылок. > Да.

Нет. GC скриптовых языков, кроме малого подмножества (кажется, PHP & Perl) использует стратегию, отличную от reference counting. Проблема использования этой стратегии связана с упомянутыми здесь замыканиями. Создавая замыкание (лямбду) и сохранняя его, вы тем самым как бы должны сделать ref_counter++ для все видимых объектов, так как из этой лямбды потенциально любой из них может быть достижим с помощью eval или других динамических методов (instance_variable_get, instance_eval, ..). Делать ref_counter++ для всех видимых объектов для каждого замыкания дорого. Используют сложные вариации mark-and-sweep.

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

>>> AFAIK там до сих пор всё основано на подсчёте ссылок.

>> Да.

>Нет. GC скриптовых языков, кроме малого подмножества (кажется, PHP & Perl) использует стратегию, отличную от reference counting.

Насчет "скриптовых языков" вообще (сферических и в вакууме, я надеюсь?) сказать не могу, но в Питоне используется именно reference counting.

> Используют сложные вариации mark-and-sweep.

В Руби - может быть. Но в данном случае именно Руби является "малым подмножеством".

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

>> Да, если поменялась модель данных в базе данных, придётся >перезагрузить веб приложение, чтобы оно почувствовало эти изменения. >Но тут уж извините, иначе нельзя.
>

>Это в динамическом языке иначе нельзя. В статическом - перегенерировал часть, инкапсулирующую взаимодействие с БД, а дальше компилятор укажет места, которые нужно править из-за несовместимости изменений. А в динамическом языке придется молиться на то, что тесты обеспечивают 100% покрытия.


В статическом языке всё безнадёжно. Проверка правильности происходит только через останов и пересборку программы. В динамическом - есть выбор. Можно точно так же остановить и пересобрать, можно править на лету. На самом деле, выбор во многом зависит от конкретной ситуации, а возможность менять на лету - от качества языка.

Если говорить конкретно про клиент-серверные SQL приложения, то, во-первых, не всегда есть возможность остановить систему вообще или остановить её надолго. Во-вторых, не все ошибки в принципе можно отловить. Например, ошибку в раздаче прав пользователям иначе как тестами не отловить и я не думаю, что type inference здесь как-то поможет. В-третьих, как правило, в большой системе есть критичный и некритичный функционал. Критичный должен работать всегда, некритичный можно исправить потом. Динамичная среда даёт свободу управлять приоритетами. В четвёртых, если систему можно (удобно) остановить и перекомпилировать, то очень многое зависит от скорости компиляции и времени, требуемого на остановку-запуск. На производстве время перерыва в работе ограничено. Если компиляция происходит 2 минуты, то это одно. Если 2 часа - то это другое. Чем более серьёзные проверки возлагаются на компилятор, тем медленнее он будет работать и тем больше доводов в пользу динамики (например, при исправлении критичной ошибки часть тестов второстепенного функционала можно отложить на потом).

Однако, конечно же, пересобрать всё с нуля - это в отдалённой перспективе более надёжно, чем править на лету, т.к. ошибки не складываются и есть понятный исходник, из которого всё происходит.

Я в лиспе работаю динамически (это быстрее в десятки раз при разработке), но если я периодически не делаю пересборку образа, то со временем у меня возникают проблемы разного рода (я теряю контроль над исходником, возникают неразрешимые циклические ссылки между определениями, мусор разного рода). Однако, не иметь свободы менять систему на лету и пересобирать её при каждом мизерном изменении - это глупый экстремизм, которому я могу найти два объяснения:
1. невежество.
2. недоступность этого подхода во многих популярных средах.

На практике, да, лисп или даже там руби мало кто использует. Но sql сервера - это динамика. Можно альтерить таблицу, не останавливая сервер. Хотя я про это уже писал :)

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

> Аргумент очевиден. Мы делали (и не доделали) сравнительный анализ системы типов плюсов и хаскеля -- на этом сайте такой оффтопик в порядке вещей -- а ты, вместо того чтобы доделать этот анализ, завел лирику "а вот в дин. языках есть бигнум". Ты можешь быть специалистом, но такое поведение настраивает меня рассматривать тебя как лирика. + прокол с чтением википедии, + полное непонимание роли указателей в плюсах.

Ну надо же, вместо того чтобы делать анализ офтопного флуда и поддержать его, я грубо попытался вернуться к теме. Создайте отдельную тему - типизация в Haskell и С++. Обсудим.

И еще раз тем, кого беспокоит ответ на вопрос темы и кто сомневается в том, что динамические языки нужны "В то время как программист на C++ спорит с программистом на Haskell о max_bound и о том, как сложно/просто/возможно/невозможно заставить их языки программирования делать то, что им зачем-то нужно, программист на динамическом языке пишет уже новую фичу в своем проекте и на таких мелочах как max_bound просто не задерживается, так как их просто нет".

Да. Попробовал вернуть к теме. Я просмотрел мельком весь флуд и обнаружил, к своему удивлению, что нормальных ответов на поставленный в теме вопрос немного. Вот один из них: http://www.linux.org.ru/jump-message.jsp?msgid=3594542&cid=3602382 Именно его проигнорировали.

Вместо этого начался флуд о С++ и Haskell . С++ я не считаю динамическим, а динамичность Haskell следует из его чистой функциональности, что не является мейнстримом динамических языков, так что это тоже офтопик. Мейнстрим это -- Perl (админы), Python (админы + google + dgango + ..), Ruby (rails), Lua (.. хмм, ну например скрипты для WoW), ...

Можно конечно и Haskell к этому ряду причислить. Но ответ на вопрос темы для Haskell и Python точно разные.

PS: Q: Зачем нужны динамические языки?

A: Программист всегда стремится к модульности, краткости, внятности и гибкости кода. Оказывается динамические языки могут помочь сделать шаг в этом направлении.

См. например http://acm.mipt.ru/twiki/bin/view/Cintro/FindFrequentWords, где показаны программы вычисления 10 самых частых слов в файле a.txt на С++, С и Ruby. Вот код на Ruby

File.open("a.txt") do |file| file.read.downcase.scan(/\w+/).select{|word| word.size > 4}.inject(Hash.new(0)){|f,word| f[word] += 1 f }.to_a.sort_by {|word, freq| -freq}[0..9].each {|word,freq| printf("%20s %5d\n", word, freq) } end

Но важно здесь отметить, что крутость не в том, что вместо каждых трёх на С++ строчек пишется она на Ruby. Изоморфизма кода не наблюдается, так как динамические языки предоставляют новые паттерны модульности и реюза. Ответ постигается сразу после попытки повторить функционал Rails на С++. Python и Ruby не фига не что-то типа bash, только с фичами нормальных языков программирования. Это инструменты не только для маленьких everyday-скриптиков. Это целостные языки, годные для больших проектов. В Ruby и Python ООП реализована в полной мере и разработчики динамических языков программирования и библиотек для них тщательно продумывают концепции поддержки кода больших проектов, и следят за читаемостью и самодокуменированностью кода (код ясен даже без комментов) (не добавляют лишних вещей, которые потенциально могут привести к фрускации).

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

> Да. Попробовал вернуть к теме. Я просмотрел мельком весь флуд и обнаружил, к своему удивлению, что нормальных ответов на поставленный в теме вопрос немного. Вот один из них: http://www.linux.org.ru/jump-message.jsp?msgid=3594542&cid=3602382 Именно его проигнорировали.

with-open-file не имеет отношения к динамизму вообще, как ни странно. Это есть в плюсах - создавая на стеке объект, мы тем самым гарантируем вызов деструктора на выходе из кадра стека.

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

> В статическом языке всё безнадёжно.

> На практике, да, лисп или даже там руби мало кто использует.

Противоречивый den73 такой противоречивый :)

> во-первых, не всегда есть возможность остановить систему вообще или остановить её надолго.

Это решается другими средствами - не языковыми.

> Например, ошибку в раздаче прав пользователям иначе как тестами не отловить и я не думаю, что type inference здесь как-то поможет.

Как меня достал такой стиль мышления. То есть если средство X не позволяет отловить всех ошибок - в топку его? Дети горькие, блин.

> В четвёртых, если систему можно (удобно) остановить и перекомпилировать, то очень многое зависит от скорости компиляции и времени, требуемого на остановку-запуск. На производстве время перерыва в работе ограничено.

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

> Однако, конечно же, пересобрать всё с нуля - это в отдалённой перспективе более надёжно, чем править на лету

О чем и речь. И даже в ближней перспективе это более надежно.

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

Я бы сказал, что это лютый п*дец.

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

tailgunner, ты глючишь.
> Противоречивый den73 такой противоречивый :)


Глюк N1. Где конкретно противоречие? Я утверждал, что лисп везде используется? Может быть, конечно, лет 5 назад я так считал, поддавшись на рекламу.

> о есть если средство X не позволяет отловить всех ошибок - в топку его?


Средство Х (Хаскель) - в топку, по другим причинам. А так, вообще, я не утверждал, что type inference не нужен и безполезен. Это - твой глюк N2.

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


Вопрос одевания трусов можно решить через голову. Но это не повод не одевать их нормально, через ноги.

> Я бы сказал, что это лютый п*дец.

Как раз во избежание его я и перезагружаю свой лисп примерно раз в неделю. Видимо, лютый п-ц - это глюк N3

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

> Где конкретно противоречие?

Ну я же написал. Между фразами:

> В статическом языке всё безнадёжно.

и

> На практике, да, лисп или даже там руби мало кто использует.

То есть совершенно безнадежное (по твоим словам) средство используется на практике. Более того, ты и сам писал о преимуществах Делфи над CL.

>> о есть если средство X не позволяет отловить всех ошибок - в топку его?

> Средство Х (Хаскель) - в топку, по другим причинам.

X в данном случае - просто переменная. Мне лично Хаскел не нравится.

> А так, вообще, я не утверждал, что type inference не нужен и безполезен. Это - твой глюк N2.

Не-а, это не мой глюк :) Я говорил о статической проверке типов (type inference может использоваться не только для нее). О твоем отношении к статической типизации - см. выше.

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

> Вопрос одевания трусов можно решить через голову. Но это не повод не одевать их нормально, через ноги.

Видишь ли, ни один вменяемый менеджер не даст тебе экспериментировать на живом сервисе. Всё отрабатывается на тестовых серверах по причинам, которые не имеют отношения к языкам.

> Видимо, лютый п-ц - это глюк N3

Не-а, это различие в менталитетах :)

Слушай (вернемся к примеру Greck с изменением схемы БД) - ты бы правда изменил схему именно на рабочем сервере, и перезапустил приложение прямо в работу?

P.S. Трусы НАдевают.

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

> То есть совершенно безнадежное (по твоим словам) средство используется на практике

Если бы ты был внимателен, то обратил бы внимание, что я упираю на динамизм SQL. Его используют, да. А ты не заметил? Другой пример - это операционка. Я его оба эти примера два или три раза приводил. И кто-то ещё приводил.

> Я говорил о статической проверке типов (type inference может использоваться не только для нее).

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

> Слушай (вернемся к примеру Greck с изменением схемы БД) - ты бы правда изменил схему именно на рабочем сервере, и перезапустил приложение прямо в работу?

Нет, конечно. В идеале, я просто делаю набор скриптов, к-рые сначала запускаю на тестовой базе, а потом, после тестирования, те же скрипты напускаю на рабочую базу. На практике это бывает сложнее. Тем не менее, факт состоит в том, что я не останавливаю и не пересобираю сервер СУБД, когда делаю alter table. Именно это я и хочу подчеркнуть, т.к. это проявление динамичной системы.

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

>> (иначе зачем тогда 100% покрытие?).
> Модуль работы с БД предоставляет интерфейсы, которые зависят от схемы БД. Все модули, которые напрямую используют эти интерфейсы, должны быть покрыты 100%. Если эти модули, в свою очередь, предоставляют другим интерфейсы, зависимые по типам от схемы БД... эффект домино.


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

>> Переименовал одну таблицу --- и всё, никакой стаитческий компилятор тебе не укажет на все запросы

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


Разумеется.

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