[info]en_dmitriid


Tigers, and lions, and bears, oh my!


Dynamic languages rule
happy
[info]dmitriid
It seems to me that dynamic languages...That is, languages which have more dynamics built in... That is, nice languages to put it simply :)) Well, they rule.

I've been browsing Jakarta Commons' source code using http://www.koders.com/ (I actualy only needed their WordUtils in order to rewrite them in ColdFusion). An then I see Validate.java:
    public static void isTrue(boolean expression, String message, Object value) {
        if (expression == false) {
            throw new IllegalArgumentException(message + value);
        }
    }

    public static void isTrue(boolean expression, String message, long value) {
        if (expression == false) {
            throw new IllegalArgumentException(message + value);
        }
    }

    public static void isTrue(boolean expression, String message, double value) {
        if (expression == false) {
            throw new IllegalArgumentException(message + value);
        }
    }

    public static void isTrue(boolean expression) {
        if (expression == false) {
            throw new IllegalArgumentException("The validated expression is false");
        }
    }


:)) Static typing is the answer to everything they say, but at what cost? :))) I wonder if this could be rewritten... ColdFusion-style:
<cffunction name="isTrue">
    <cfargument name="expression" type="boolean" required="yes">    
    <cfargument name="message" type="string" required="no">
    <cfargument name="value" type="any" required="no">  
	
	<cfset msg=IIF(IsDefined('arguments.message'), DE(arguments.message), DE("The validated expression is false"))>
	<cfset v=IIF(IsDefined('arguments.value'), DE(arguments.value), DE(""))>
	
	<cfif arguments.expression EQ false>
		<cfthrow type="IllegalArgumentException" message=msg & ToString(v)>
    </cfif>
</cffunction>


Key moments here are required="true|false" in argument definitions and the IsDefined('arguments....') function which, well, defines whether optional arguments exist. Oh, and don't forget about type="any" which allows you to pass arguments of any type. And the ToString function :)

Function overloading - is, undoubtedly, great. But I'll trade it IsDefined most of the time (when it's uses are justified, of course :) )

PS. Correct me if I'm wrong, but does Java really not have access to the array of arguments passed to a function? And I'm not talking about Variable arity.

Coldfusion и XML
happy
[info]dmitriid
It is a major pain in the nether regions of the body to work with a language which provides reasonable tools for working with XML and provides no sane tools to modify XML. I'm talking about ColdFusion.

Suppose we have the following piece of XML:
<xml>
    <root>
        <elem>
            <value>Text</value>
        </elem>
    </root>


If we read this piece into a variable called xmlDoc, we have immedate access to the value "Text":

txt = xmlDoc.root.elem.value.xmlText;


Now txt contains, as you may have guessed it, a string, "Text".

Moreover, if we have quite a handful of such elements, we may use an extremely convenient function XMLSearch which accepts (an unspecified subset of) XPath and returns an array of found elements.

A real-world example now. Here's a stripped-down localization file from the project I'm working on::

<?xml version="1.0" encoding="UTF-8"?>
<strings>
	<nspace NAME="global">
		<string CRC="73FB418E8CCD929E219338A555AA7EA4">
			<original>You need to login first</original>
			<localized/>
		</string>
		<string CRC="99DEA78007133396A7B8ED70578AC6AE">
			<original>Login</original>
			<localized/>
		</string>
	</nspace>
	<controller NAME="admin">
		<action NAME="cities">
			<string CRC="FD8459135F9464065B708800B0BDF6D8">
				<original>Add a new city</original>
				<localized/>
			</string>
			<string CRC="F67FDD86A499050E0585BCA9EA023188">
				<original>Add city</original>
				<localized/>
			</string>
			<string CRC="4505DE1F3D02176AA6F1403778C5ADD1">
				<original>Region:</original>
				<localized/>
			</string>
		</action>
	</controller>
</strings>


Searching across this monster of a file is trivial:
searchString = "/strings/controller[@NAME=""admin""]/action[@NAME=""cities""]/string[@CRC=""CRC""]";
elems = XmlSearch(xmlDoc, searchString);

/* If there's only one elems, we return it (simplified example): */

return elems[1].localized.xmlString;
where CRC is calculated using obscure Vodoo rituals :)

Now, the question is: what if we want to change the value oа this element? The procedure required to do that evokes an unbearable desire to nuke Macromedia offices :)

Scanning thorugh the docs reveals that the only standard procedure to change the desired value of a tag involves the use of ArrayAppend function on the array of "value" from the array of "elem" from the array of "root"...

That is... You can find an element, but you cannot manipulate it directly. You have to take the root element. Then you have to take an array of first-level elements anв find the desired one. In that element you once again take an array (of second-level elements) and find the desired one. In that element you take an array of third-level elements and find the desired one. And finally, you take an array of fourth-level elements and find the desired one. If such an element does not exist, you append it to the array of fourth-level elements. Save.

Anyway, here's what it looks like in the end:
// Add a new string
ArrayAppend(xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].XmlChildren, XMLElemNew(xmlDoc, "string"));

// Find its position
stringIndex = ArrayLen(xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].XmlChildren);

// Change its attribute
xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].string[stringIndex].xmlAttributes.crc = Hash(t);

// Add "original" to it
ArrayAppend(xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].string[stringIndex].xmlChildren, XMLElemNew(xmlDoc, "original"));

// Find original's position
orgIndex = ArrayLen(xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].string[stringIndex].xmlChildren);

// Add text
xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].string[stringIndex].original.xmlText = t;

// Add "localized"
ArrayAppend(xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].string[stringIndex].xmlChildren, XMLElemNew(xmlDoc, "localized"));

// Obtain its index
locIndex = ArrayLen(xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].string[stringIndex].xmlChildren);

// Add text
xmlDoc.strings.xmlChildren[controllersIndex].action[actionsIndex].string[stringIndex].localized.xmlText = '';


:)))

I am only grateful that I had to write this function only once. And it took me the better part of the day...

Named Parameters
happy
[info]dmitriid
Ever since I saw Lisp I've sorely missed named function parameters. What the heck is that? Ok, here goes...

Lisp examples are quoted directly from Practical Common Lisp

Let's refresh our knowledge of WinAPI - the dearly beloved API of all Windows developers. For instance, ShellExecute:
HINSTANCE ShellExecute(      
    HWND hwnd,
    LPCTSTR lpOperation,
    LPCTSTR lpFile,
    LPCTSTR lpParameters,
    LPCTSTR lpDirectory,
    INT nShowCmd
);
On the whole I think I remember which parameters this function requires and why. Not too clearly though. I do remember the first three. The fourth might spring to mind while writing the function. The last too however, are quire elusive and I'm never quite sure which goes where and when. The problem gets worse if you remember that som parameters, hwnd, lpParameters, lpDirectory in our case, are optional and can be replaced with NULLs. So, we would quite often invoke this function like this::
 hResult = ShellExecute(NULL, "open", "path/to/file", NULL, NULL, SW_SHOWDEFAULT);
Scary, huh? Now imagine if we could write this function like this:
 hResult = ShellExecute(operation="open", file="path/to/file");
Beautiful. Now, this is what named parameters are all about.

Let's go back to Lisp. Let's consider the following function:
 (defun foo (&key a b c) (list a b c))

This function accepts three parameters and simply listst them in their order. This is how this function behaves when we invoke it in numerous ways:
(foo)                ==> (NIL NIL NIL)
(foo :a 1)           ==> (1 NIL NIL)
(foo :b 1)           ==> (NIL 1 NIL)
(foo :c 1)           ==> (NIL NIL 1)
(foo :a 1 :c 3)      ==> (1 NIL 3)
(foo :a 1 :b 2 :c 3) ==> (1 2 3)
(foo :a 1 :c 3 :b 2) ==> (1 2 3)

Note the last line. Even though the order or parameters is incorrect, the function still behaves as designed. Now, that's the beauty and power of named parameters. A developer now only needs to know which parameters a function requires, not their not their order.

Unfortunately none of the mainstream languages support named parameters, not natively at least. That is why invoking a function (especially a WinApi function) is a long and tedious process whereas we could simply make do with passing a limited number of named arguments (as my example with ShellExecute shows).

I am currently developing in ColdFusion and it supports named parameters natively (though you cannot honestly call it a mainstream language):
<cffunction name="function" access="public">
    <cfargument name="arg1" type="numeric" required="yes">
    <cfargument name="arg2" type="string" required="no">
    <!--- и так далее --->


</cffunction>
This function is invoked as follows:

<cfset function(arg1=1, arg2='string')>
As in Lisp, the order of arguments is not important as long as they are named.

Some languages (scripting languages, mostly) emulate this behaviour through the use of hashes. PHP anyone?

function a_func($params)
{
    if(isset($params['arg1'])) /* do stuff */
    if(isset($params['arg2'])) /* do stuff */
}
 
/* Calling the function */
$result = a_func(array('arg1' => 123, 'arg2' => 'a string'));
That is, we actually pass an array, but it serves our purpose well enough. Ruby employs exactly the same technique:

# find from ActiveRecord
      def find(*args)
        options = extract_options_from_args!(args)
        validate_find_options(options)
        set_readonly_option!(options)

        case args.first
          when :first then find_initial(options)
          when :all   then find_every(options)
          else             find_from_ids(args, options)
        end
      end

 
# Calling the function:
Person.find(:first, :order => "created_on DESC", :offset => 5)
Person.find(:all, :group => "category")
Person.find(:all, :offset => 10, :limit => 10)
# where Person is an object of type Activerecord
However, none of these can even compare to Lisp's implementation. ColdFusion, for instance, doesn't accept an arbitrary number of parameters (see Lisp's &rest). Hashes both in PHP and Ruby are rather cumbersome because implementation of the function may become convoluted (or you have to resort to using less-than-safe extract or extract_options_from_args! functions). I'm not even talking other languages like С/С++, C# and Java :). Some languages though, like Haskell, Erlang and Nemerle, have pattern matching allows the developer to work arounв named parameters in a very elegant manner, but that is a story for another day.

Home