How to use Option Type Pattern in a language that doesn’t support generics?

I’ve been interested to start using the Null Object / Option Type approach for replacing my old habits of null-checking multiple parts of my code. But, from the many examples I saw out there, it seems it’s a pattern used in conjunction with generics.

Great for C#, Java, Haxe and a bunch of others I’m sure.

NOT so great for ActionScript 3.0 (which is what I was intending to use it for).

So, am I under the wrong impression that this won’t be possible / worthwhile in a language that doesn’t support Generics? Or is there a way to pull it off without them?

NOTE: It seems the “Null Object” pattern shown in this PatternCraft tutorial doesn’t quite resemble the way Option Type was described in some of the other discussions in this stackexchange site. His way looks more like a factory class that spits out a Null??? derivative of some base-class. I was hoping there could be a way to create Null-Objects without needing to write a dedicated class for every single case scenarios where a null-check would typically be used.


EDIT: My apologies, I didn’t realize “Null Object” and “Option Type” were two completely different beasts. For the sake of keeping the answers and feedback relevant to the question though, I only changed the title (was originally How to use Null Object / Option Type Pattern in a language that doesn't support generics?).

5

There is major difference between Null Object pattern and Option types.

Null Object is pure OOP (thus no generics) pattern, where one object implements abstract class / interface in such a way, that calling the method through the interface is same as not calling the method at all. That means the caller has no idea that type of instance is a Null object. So these two cases are equivalent:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>// without null object
IInterface obj = null;
if(obj != null)
obj.method()
// with null object
IInterface obj = new NullObject();
obj.method()
</code>
<code>// without null object IInterface obj = null; if(obj != null) obj.method() // with null object IInterface obj = new NullObject(); obj.method() </code>
// without null object
IInterface obj = null;
if(obj != null)
    obj.method()

// with null object
IInterface obj = new NullObject();
obj.method()

Option types on the other hand are type-safe way to ensure the caller of the method knows that there is possibility that variable might contain “no valid value”. This gives compiler power to either warn or error when programmer tries to call method on variable, that might contain null.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>[PSEUDOCODE (that looks like C#)]
// case A
Option<IInterface> obj = getObject();
obj.Method() // ERROR, possible "Null reference exception"
// case B
Option<IInterface> obj = getObject();
if (obj.HasValue)
obj.Method() // OK, compiler knows that obj has valid value thanks to the if
</code>
<code>[PSEUDOCODE (that looks like C#)] // case A Option<IInterface> obj = getObject(); obj.Method() // ERROR, possible "Null reference exception" // case B Option<IInterface> obj = getObject(); if (obj.HasValue) obj.Method() // OK, compiler knows that obj has valid value thanks to the if </code>
[PSEUDOCODE (that looks like C#)]
// case A
Option<IInterface> obj = getObject();
obj.Method() // ERROR, possible "Null reference exception"

// case B
Option<IInterface> obj = getObject();
if (obj.HasValue)
    obj.Method() // OK, compiler knows that obj has valid value thanks to the if

But I believe option types don’t make much sense in language, that doesn’t have them as language feature (eg. most OOP languages), because compiler is not implemented as to detect such things as the first case (unless you use some kind of static code correctness checking). So you gain nothing against normal null check. Null object pattern on the other hand is natural in all OOP languages. Even those without generics.

Good example of OOP language having support of Option type is C#’ Nullable. You know value types always have valid value and Nullable allows you to specify cases where variable might not contain valid value. But this is only for value types.

6

Option is isomorphic to a collection which can only ever be empty or contain a single element. So, you implement it the same way you would any other collection.

If you can implement a list, set, map, tree, heap, stack, array, trie, treap etc. in your language, then you can implement Option in exactly the same way.

See AS3Commons Collections for a comprehensive collections framework implemented in ActionScript. (Note: it doesn’t seem to be as powerful as Scala’s, but it can at least compare favorably with Java’s.) In essence, without parametric polymorphism, you lose type-safety, the same way you do with Java 1.1, .NET 1.0, C, Pascal, Modula, etc.

The purpose of option types is to let the compiler know exactly where a value may be empty in a language where null simply does not exist (typical for any language that supports algebraic data types). This way, the compiler can give compiler-time errors if you forget to check for emptyness. Here’s an example in Rust, an imperative language with a C-like syntax:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>let my_number : Option<int> = read_number();
return 2 * my_number; // compile error
</code>
<code>let my_number : Option<int> = read_number(); return 2 * my_number; // compile error </code>
let my_number : Option<int> = read_number();
return 2 * my_number;          // compile error

This won’t compile because my_number does not contain an int but an Option<int> (i.e. an int that may be empty). The compiler does not allow multiplication on Option<int>.

Therefore, it is necessary to pattern match my_number in order to extract its value:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>let my_number : Option<int> = read_number();
match (my_number) {
Some(my_actual_number) =>
return Some(2 * my_actual_number); // ok
None ->
return None; // fallback if it's empty
</code>
<code>let my_number : Option<int> = read_number(); match (my_number) { Some(my_actual_number) => return Some(2 * my_actual_number); // ok None -> return None; // fallback if it's empty </code>
let my_number : Option<int> = read_number();
match (my_number) {
    Some(my_actual_number) =>
        return Some(2 * my_actual_number);  // ok
    None ->
        return None;                        // fallback if it's empty

The pattern matching forces the programmer to handle every possible scenario: in this case, the None case. This is how it prevents the typical “forgot to check for null” problem.

However, in a language where null is pervasive, option types aren’t nearly as useful since everything can already be null anyway. Therefore the compiler can’t really help you (since inferring the nullability would require solving the halting problem).


The null object pattern not the same thing, but it is a related concept.

In languages that have first-class support for option types, one is permitted to apply an operation to the internal object inside the option type, if it exists. It serves as a shortcut for the common activity of “do X to the object, but if it’s empty then forget about it”. This process is typically called “mapping” and this operation can be defined for all option types.

The map operation takes an option object (Option<T>), as well as a function that can act on the internal object (T -> R), and produces the result of the function wrapped in an option object (Option<R>).

In fact, the example above can be rewritten much more succinctly using a map combined with an anonymous function:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>let my_number : Option<int> = read_number();
return my_number.map(
// use anonymous function to specify what to do
|my_actual_number| 2 * my_actual_number
);
</code>
<code>let my_number : Option<int> = read_number(); return my_number.map( // use anonymous function to specify what to do |my_actual_number| 2 * my_actual_number ); </code>
let my_number : Option<int> = read_number();
return my_number.map(
    // use anonymous function to specify what to do
    |my_actual_number| 2 * my_actual_number
);

Map can be thought of as a recipe that:

  • If the option object is not empty, then apply the provided function and return the result in a Some(...).
  • If the option object is in fact empty, then do nothing and just return None.

In the null object pattern, one uses a “null” class that possesses same methods as the non-null class (they could be siblings in the inheritance hierarchy), but arranged in such a way that the operations on the “null” class simply do nothing. Hence, the null object pattern is similar in that it accomplishes this same goal, albeit in a different, more object-oriented/duck-typing way.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật