使いたくない型を見えなくする #FsAdvent
この記事はF# Advent Calendar 2015 - connpassの2日目です。
同僚へのイタズラネタを紹介したいと思います。
AutoOpenと組み合わせて混乱に陥れてやりましょう。
標準ライブラリの中には、古くなったり、挙動が紛らわしいという理由で使うべきではないクラスや関数があります。
どこかのサイトから当時は適切だった古いコードを参考にしてきて、うっかり使ってしまう人もいるでしょう。
こんな困った人のコードはコンパイルエラーにしてやる!
一部のメンバのみ制限する
例えば、System.Text.Encoding.UTF8
プロパティとSystem.Text.UTF8Encoding
クラスの2つで、BOMがどう扱われるか直ぐに言えますか?
System.Text.Encoding.UTF8
はBOMが付きます。一方、System.Text.UTF8Encoding
はコンストラクタでBOMの有無を指定できます。
BOMを扱わないシステムを扱っている場合は、System.Text.Encoding.UTF8
をなるべく使ってほしくないですね。
module System.Text.Encoding let UTF8 = ()
このようなモジュールを定義すると、System.Text.Encoding.UTF8
の定義を上書きできます。
そして、System.Text.Encoding.UTF8
を使おうとすると型が合わずコンパイルエラーになってしまいます。
コンパイルエラーがやり過ぎだと思ったら、ObsoleteAttribute
を付けて警告にもできます。
module System.Text.Encoding let [<System.Obsolete>]UTF8 = System.Text.Encoding.UTF8
この方法はUTF8
プロパティのみ上書きされ、他のメンバは普段どおり使用できます。
使ってほしくないクラス、モジュールを制限する
次の例は、.NetにはXMLを扱うには2つの方法があります。
古くからあるSystem.Xml
名前空間と、Linq to XmlのSystem.Xml.Linq
名前空間の2つです。
System.Xml
名前空間にあるクラスは使いづらいので、プロジェクト全体で使わせたくない上に、何も指示しないとSystem.Xml
のクラスを使う人までいます。
使わせたくない!コードレビューの時では遅いのだ!
先程は同名のモジュールを定義して、同名のメンバを定義しましたが、今度は同名のクラスを定義します。
namespace System.Xml type XmlDocument private() = class end
もともとのSystem.Xml.XmlDocument
にアクセスしようと思っても、上記の定義が邪魔をして使えなくなってしまいます。
open System.Xml let x = XmlDocument() (* この型にアクセスできるオブジェクト コンストラクターはありません *)
めでたしめでたし。
まとめ
こういうのはLintの仕事だと思いました。