Есть старая шутка о том, что любая достаточно сложная система, написанная на языке со статической типизацией, содержит неполную, низшую реализацию Lisp.
Поскольку ваши требования, как правило, усложняются по мере развития проекта, вы часто в конечном итоге обнаруживаете, что общие идиомы в объектных системах статического типа в конечном итоге попадают в стену. Иногда стремление к размышлению - лучшее решение.
Я доволен динамически типизированными языками, такими как Ruby, и статически типизированными языками, такими как C #, но неявное отражение в Ruby часто делает более простой и легкий для чтения код. (В зависимости от требуемой магии метапрограммирования, иногда сложнее написать).
В C # я обнаружил проблемы, которые не могли быть решены без размышления из-за информации, которой у меня не было до времени выполнения. Один пример: при попытке манипулировать каким-либо сторонним кодом, который генерировал прокси для объектов Silverlight, запущенных в другом процессе, мне пришлось использовать отражение, чтобы вызвать конкретную строго типизированную «универсальную» версию метода, потому что для маршаллинга требовался сделать предположение о типе объекта в другом процессе, чтобы извлечь из него нужные нам данные, и C # не позволяет указывать «тип» вызова универсального метода во время выполнения (кроме как с помощью отражения техники). Я думаю, вы могли бы утверждать, что наш инструмент был своего рода фреймворком, но я легко мог представить случай в обычном приложении, сталкивающемся с подобной проблемой.