Tuesday, September 30, 2008

Hidden Functions

Let's talk about hidden functions. What do I mean by that? When I refer to a hidden function, I mean one that exists in some non-public context, and is not directly accessible from the outside. There are several ways one can realize this goal, and we'll talk our usual stroll through some appropriate languages and how they approach his problem.

Scheme



Let's start with Scheme. Assuming the follow content in a file called hidden.scm:

(define (obvious)
(define (hidden) `hidden)
(hidden))


We can then try it out using guile -l hidden.scm:


guile> (hidden)

Backtrace:
In standard input:
1: 0* (hidden)

standard input:1:1: In expression (hidden):
standard input:1:1: Unbound variable: hidden
ABORT: (unbound-variable)


We see that (hidden) is not directly accessible from the outside, however...


guile> (obvious)
hidden


It is still defined and reachable through the intermediary function (obvious). This is great for all the expected black box reasons:


  1. Users/developers can be presented with a consistent interface

  2. Purpose can be separated from implementation details, which means that

  3. Testing is easier to do, which means that

  4. Refactoring is easier to do, whether literally just an improvement to internal clarity and readability, or wherein the inputs and outputs remain the same expressions, but other improvements occur, such as faster speed of execution, reduced memory footprint, or both



Perl



I've written about Perl a bit more than I expected to lately. Let's continue with that, and see an example in Perl.


#!/usr/bin/env perl
# hidden.pl

use constant HIDDEN => 'hidden';

sub obvious {
sub hidden { HIDDEN }
hidden();
}

sub obvious2 {
my $hidden = sub { HIDDEN };
$hidden->();
}

print obvious() . "\n";
print obvious2() . "\n";
print hidden() . " is really not that hidden\n";
print $hidden->() . "\n";


Executing this program at the command line with perl hidden.pl produces the following output:


hidden
hidden
hidden is really not that hidden
Undefined subroutine &main:: called at hidden.pl line 19.


I like constants for values that don't change and are reused - call me crazy. The examples obvious() and obvious2() are very similar. The only difference is that the function which we wish to hide is declared either as a traditional subroutine or as a subroutine reference. Why the distinction?

The reason is revealed when we make a direct call to hidden(). Perl does not scope the declaration of hidden() within obvious() as Scheme does. hidden() is accessible from outside obvious() where it was declared. However, attempting to call $hidden->() at the top level fails, because Perl does scope $hidden inside obvious2() where it was declared.

I'm not a real Perl guru. I get by in the language, but I'm sure someone who frequents Perl Monks or the like could explore this idea further.

Ruby



Despite Ruby's comprehensive support for programming in the functional paradigm, it is commonly thought of as an object oriented language, not without cause. Many people are most familiar with the notion of hiding executable code through the process of private or protected access control common in OO languages.

I won't give an example of traditional OO access control in Ruby here. Rather, I'll explore ideas more akin to the preceding Scheme and Perl examples that use nested function declarations. Some of this code is intentionally broken and/or strange-looking.


class Owner

HIDDEN_PROC = lambda { %q[hidden value from Proc] }

def obvious
def hidden; %q[hidden value]; end
hidden.gsub(%r[hidden], %q[obvious])
end
def obvious2; hidden + %q[ from obvious2]; end
def obvious3; HIDDEN_PROC.call; end

end

if (__FILE__ == $0)
o = Owner.new
puts o.obvious
puts o.obvious2
puts o.obvious3
begin
puts o.obvious.hidden
rescue
puts %q[Could not access o.obvious.hidden]
end
begin
puts o::HIDDEN_PROC.call
rescue
puts %q[Could not access o::HIDDEN_PROC.call]
end
puts o.hidden + %q[ - not really all that hidden]
end


Let's take it for a spin with ruby hidden.rb. (Note that the boolean expression (__FILE__ == $0) is only truthy when the file is executed directly like this, and not when the file is required in the manner of a library file.)


obvious value
hidden value from obvious2
hidden value from Proc
Could not access o.obvious.hidden
Could not access o::HIDDEN_PROC.call
hidden value - not really all that hidden


hidden() is callable from within obvious(), and we can even do a regular expression substitution on its value. Fine and dandy. Its hidden status is called into question by it being accessible from within obvious2(), even though it was not declared there. Let's ponder why that is for a moment.

If a function in Ruby were genuinely hideable, as in Scheme, it would not be so available. However, one must keep in mind that there are technically no functions in Ruby at all: they're methods, and that distinction makes all the difference. A method is a function that is attached to an object (or class), and what would it imply if a method were not accessible by its owning object? It wouldn't be much of a method, and that's where Ruby's OO nature wins out.

In order to restrict access to some executable code within an object, we can either comply with OO practice and use traditional access control, or do something akin to obvious3(), in which we define a callable HIDDEN_PROC that is not publicly accessible, but is callable from within obvious3() (for example). If we wanted even more separation, we could define HIDDEN_PROC as a lexical variable within the obvious3() method, rather than as a class Constant. Such an approach would be very similar to the Perl example's definition of $hidden.

Erlang



On to Erlang, which has some interesting features regarding exporting of functions. Here's our file hidden.erl.


-module(hidden).
-author("Kevin C. Baird").
-purpose("Demonstrate hidden functions in Erlang").
-export([obvious/0]).

obvious() -> hidden().
hidden() -> 'value from hidden'.


Here's our erl session that uses it:


$ erl
Erlang (BEAM) emulator version 5.5.5 [source] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.5.5 (abort with ^G)
1> c(hidden).
{ok,hidden}
2> hidden:obvious().
'value from hidden'
3> hidden:hidden().

=ERROR REPORT==== 30-Sep-2008::10:05:09 ===
Error in process <0.31.0> with exit value: {undef,[{hidden,hidden,[]},{erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {undef,[{hidden,hidden,[]},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_loop,3}]} **


Because only obvious is exported, it is the only function publicly available. We could have used as complex a basis as we wanted to determine its eventual value, all of which could be safely hidden within our hidden module. That's what encapsulation's all about.

Haskell



Another purely functional language I've discussed is Haskell. In fact, its strongest advocates would probably deny Erlang the label purely functional, as it does not segregate side effects as fully as Haskell does.

In any case, we can have a quite small Hidden.hs file:


-- Hidden.hs
-- Kevin C. Baird
-- Demonstrate hidden functions in Haskell

obvious = hidden
where hidden = "value from hidden"


That executes as you'd expect by this point, as seen in hugs:


$ hugs Hidden.hs
__ __ __ __ ____ ___ _________________________________________
|| || || || || || ||__ Hugs 98: Based on the Haskell 98 standard
||___|| ||__|| ||__|| __|| Copyright (c) 1994-2005
||---|| ___|| World Wide Web: http://haskell.org/hugs
|| || Bugs: http://hackage.haskell.org/trac/hugs
|| || Version: September 2006 _________________________________________

Haskell 98 mode: Restart with command line option -98 to enable extensions

Type :? for help
Main> obvious
"value from hidden"
Main> hidden
ERROR - Undefined variable "hidden"

Wednesday, September 17, 2008

Boston, San Francisco and SDD

My colleague Jim Lindley and I will be going to Boston for a few days for our employer. We do TDD/BDD with RSpec and Rails currently, and the folks in the Boston office are at some point along a similar continuum. We'll show them what we do, they'll show us what they do, we'll learn and grow and laugh and share and love, etc. Then I'm off to San Francisco for some interviews related to my planned relocation out there.

Yesterday, I came across a blog post by Paul Barry about SDD with Rails. The two upcoming trips already had me thinking about my workflow, and Jim and I had been talking about trying move another abstraction step up from our current speccing practice, and SDD seems like a good match for our next project. It's a rewrite of an existing app that is currently in a different language - our job would be to match it feature-for-feature and also to make some necessary changes and additions.

SDD seems like a good way to keep the QA folks who already know how the app should work more involved in the the speccing process in a way that actually has impact. That's the beauty of having the human-readable descriptions be executable.

Paul also links to Bryan Helmkamp's talk on SDD at GoRuCo2008, which is very good. I would encourage anyone to read Paul's post and watch Bryan's talk.