В RSDN-овском обсуждении Billion-dollar mistake тов.Кодёнок продемонстрировал, как тип Maybe из функциональных языков:
data Maybe a = Nothing | Just a |
мог бы использоваться в C++/C# для сокращения количества проблем с null-указателями:
struct Maybe<A> {}; struct Nothing<A> : Maybe<A> {}; struct Just<A> { A value; }; void fun(Maybe<A> x) { print(x.value); // type ERROR if (x is Just<A>) print( (Just<A>)x.value ); // OK } |
Мои скромные познания в C# позволяют думать, что это пример C#-ного кода. В C++ такой подход выглядел бы более сурово, за счет использования dynamic_cast-ов или каких-то других фокусов. Поэтому я думаю, что подход с типами Maybe, Nothing и Just в C++ не прошел бы. Для C++ нужно было бы иметь что-нибудь более заточенное под C++, а не кальку с функционального языка.
Например, можно было бы использовать Boost-овский Optional. Что-то вроде:
// Здесь мы не должны получать NULL. void g( A & a ) { ... } // А вот здесь мы можем получить NULL или не-NULL. void fun(boost::optional<A*> x) { if (x) g( **x ); // OK } |
Но для Boost.Optional null-указатель является допустимым значением. Поэтому можно было бы создать более простой аналог Boost.Optional, заточенный специально под хранение указателей:
// Класс, который не может хранить внутри себя нулевые указатели. template< class T > class not_null_ptr { public : not_null_ptr( T * ptr ) // Вспомогательная функция ensure_not_null порождает исключение // если получает нулевой аргумент. : p_( ensure_not_null( ptr ) ) {} ... T * get() const { return p_; } ... private : T * p_; }; // Класс, который может хранить внутри себя нулевые указатели. template< class T > class nullable_ptr { public : nullable_ptr( T * ptr ) : p_( ptr ) {} ... bool is_null() const { return !p_; } // Безопасный доступ к указателю. not_null_ptr<T> get_not_null() const { return not_null_ptr<T>( p_ ); } // Прямой доступ к указателю. T * get_any() const { return p_; } ... private : T * p_; }; // Здесь мы не должны получать NULL. void g( not_null_ptr< A > a ) { ... } // А вот здесь мы можем получить NULL или не-NULL. void fun( nullable_ptr< A > x ) { if( !x.is_null() ) g( x.get_not_null() ); // OK } |
Такой подход мне нравится еще и тем, что если у нас нет желания обрабатывать нулевой указатель, мы можем сразу вызывать get_not_null и получать либо не нулевой указатель, либо исключение.
PS. Это всего лишь набросок того, что я бы хотел видеть в C++ в качестве средств борьбы с нулевыми указателями вместо Maybe. Реальное решение должно быть более продвинутым. Например, должны решаться вопросы владения указателем (совмещение nullable_ptr с auto_ptr/unique_ptr и/или shared_ptr). Кроме того, в C++ null-указатель еще не самая страшная проблема – повисшие и запорченные указатели куда страшнее.
Но я хотел показать, что просто так тянуть Maybe из функциональных языков в C++ не нужно. Поскольку в каждом языке есть свои собственные тараканы, с коими нужно считаться.
PPS. Вот интересно, если бы шаблоны в C++ были с самого начала, могли ли классы вроде nullable_ptr/not_null_ptr появиться в стандартной библиотеке C++ сразу? Чтобы функции std::strcpy имели прототип:
not_null_ptr<char> strcpy( not_null_ptr<char> dest, const_not_null_ptr<char> src) |
:)
8 комментариев:
Конечно, под C++ более правильным будет аналог boost::optional, но суть же останется той же. Да и такой тип не обязан вообще-то хранить в себе именно указатели, в том же окамле он скорее хранит значения, хотя может и ссылки конечно.
в maybe и прочих паттерн матчингах все держится на проверке компилятором полноты этого самого матчинга. В плюсах подобные решения быстро проявляются как вирус дестабилизирующий программу. так что у меня на этот счет суровое правило - видишь конструкцию, которая вместо выполнения контракта, перекладывает его на клиентов - удали сразу пока еще не поздно.
Void-safety - вот, на мой взгляд, правильное решение из языка Eiffel. Жаль, что работает пока только в экспериментальном режиме. Однако обещают в ближайшее время допилить, ведь необходимо произвести изменения во всем коде. Но тенденция уже видна - все новые дополнения и изменения будут выходить только в void-safety варианте.
2Quaker: вроде как на днях вышла EiffelStudio 6.5. Может там статус с экспериментального сменился на стабильный?
2Rubanets Myroslav:
>В плюсах подобные решения быстро проявляются как вирус дестабилизирующий программу. так что у меня на этот счет суровое правило - видишь конструкцию, которая вместо выполнения контракта, перекладывает его на клиентов - удали сразу пока еще не поздно.
А можно эту мысль развернуть (слайды! слайды! -- скандировали зрители :)
>Может там статус с экспериментального сменился на стабильный?
Пока нет: http://n2.nabble.com/Re-EiffelStudio-6-5-releases-td4146106.html#a4146106
2Евгений Охотников:
эхх да где ж его времени столько взять то ... Может быть наскребу на блог пост :) тогда и будет. (те. пока неизвестно когда).
2Rubanets Myroslav: ничего, подождем
Отправить комментарий