Lazy::Bool is my first module in CPAN (The Comprehensive Perl Archive Network). It is a simple module (only 60 lines) and few methods/operators but can be useful in some situation. The source code can be found in my github.
1 2 3 4 5 6 7 8 9 10 11 12 13
Sometimes we have expensive operations in our code (like uses lots of CPU, Memory, etc). We can wait until the last second to evaluate this kind of expressions if we can. Imagine an imaginary video processing module and we need check many parameters to validate one file like: size, format, codec, extension, etc. It is easy to fetch the size of one file but read the file to fetch some informations can be expensive (we have I/O, etc). We can avoid one expensive process if the size of the file is not ok (like more than the limit, or less than 1 Kb). Of course we can write the validation subroutine thinking in this scenario or… we can use my Lazy::Bool!
How it works
In perl we can overload many operators using the pragma overload. One of this operators is the ‘bool’, used for type conversion. Perl has a small set of data types (scalar, array, hash, subroutine, etc) but one scalar can be used as a text, number or boolean (the context is important). If we use one scalar in boolean context, we can control like this.
1 2 3 4 5 6 7 8
To create an instance of Lazy::Bool we need to use the bless keyword. I can bless any reference (normally we use a hashref to simulate the internal state of the object) and the semantic of the method calling is similar to Python: the first argument is the class or object.
For this module I’m blessing a reference to a subroutine. It is essential for be lazy as much as we can. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
The shift keyword just return the first argument and remove it from the array. All subroutines in Perl receive just one array with all parameters. If I want to call a subroutine and pass more than one array I need to use references. Strange? Maybe, it is a simple way to work with multiple parameters and do this:
1 2 3 4 5 6 7 8 9 10 11
In my module I have a blessed reference for a subroutine. I will evaluate the value only in boolean context. Sounds good! But If I want to build one complex expression using or, and, not?
I can’t override the && and || BUT I can override the bit operators &, | and !, to build complex objects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
And you can do the same with | and ! operators.
There are two helper methods, true and false, to return lazy values of true and false (1 and 0).
Unfortunately this module is a beta version and it is not ready to production. I need to think in two details:
I need to implement:
- a shortcut in and / or operations
- a cache to prevent evaluate the same expression twice
But I don’t know what is the best way to do this. I’m using & and | operators similar to logical and/or but &/| does not have any shortcut. Maybe I can put a huge observation in the documentation about this.
The question about cache is interesting. In some cases I can’t ‘memoize’ the result. I have two options:
- create another class like Lazu::Bool::Memoized to do this, or
- add an extra parameter in the contructor, like cached => 1
I’m very interesting in your opinion! Please give me some feedback :)
From version 0.03 there all boolean expression now supports shortcut and there is a new class, Lazy::Bool::Cached who memoize the value of the expression.
How to install
To install this module is simple:
bash$ cpan Lazy::Bool
I try to do this module in Ruby and I realize it is not possible see here. In Ruby we have only two “false” values: nil and false. And it is HARD CODED in the code. I can’t extend the FalseClass (in fact I can but if I do this I loose the ‘new’). I have no options to do this transparent to the user.
The same thing in Java: I have the Boolean wrapper class but it is final. But I can emulate the same thing in Python using the
__nonzero__ special method like this:
1 2 3 4 5 6 7 8 9 10 11 12
Build a dynamic proxy to one real object can be very helpful in many situations. You can find this in Hibernate (the Java ORM solution) if you choose working with Lazy Initialization.
Perl, Python, Java, Ruby or PHP: each language has some advantages to do something. I can’t choose one language just based on one aspect. We need to consider the community, the environment, tools, etc. Perl is a good choice for software development in general (web, desktop, backend services) but it is not the only language capable to do X. We need to think about many aspects to decide one (or more) for our next project and be happy.