"Andrew Hunt" <andy / toolshed.com> wrote in message
news:slrn9ejav8.lma.andy / workbench.toolshed.com...
> On Fri, 27 Apr 2001 16:33:05 GMT, Steve  Holden <sholden / holdenweb.com>
wrote:

Hi /\ndy,

About an hour or so after your last post to me, I realized you're one of the
two authors on the "Programming Ruby" book.

Which, of course, was the Ruby book I was telling you I had ;-).

...snip...
>
> I personally like the style and dynacism of Ruby.  For instance, to
declare
> a class that inherits from another class you simply have:
>
> class Foo < Bar
> def myMethod
> File.new ("test.dat", "w") { |f|
> f.puts "Hello world!"
> }
> end
> end

A SmallScript version could be written as:
=========================================
class name=Foo extends=Bar {
    method {
      myMethod
        File('test.dat','w') << 'Hello world!'.
    }
}

<!-- Run it here -->
{Foo().myMethod}

======

--- OR as single line scripts with just:

{File('test.dat','w') << 'Hello world!'}

--- OR ---

{File('test.dat','w').write('Hello world!')}

--- OR ---

{File('test.dat','w').puts('Hello world!')}

=========================================

The above assumes you have a class <File> with a constructor that takes two
arguments (<aFilePath>,<aFilePermissions>) which returns instances that
implement the <IStream> interface. The "garbage collector and/or exit"
finalization will automatically close the <File> streams left open in the
above examples.

The same SmallScript compiler will also process this (XML form of Smalltalk)
identically:
=============================

<class name=Foo extends=Bar>
<?method class=Foo [ "<-- specifying class is unnecessary"
myMethod
    (File open: 'test.dat' withPermissions: 'w')
        nextPutAll: 'Hello world!'
]?>
</class>
[Foo new myMethod].

--- Which is Equivalent To ---
class name=Foo extends=Bar.
method class=Foo [
myMethod
    (File open: 'test.dat' withPermissions: 'w')
        nextPutAll: 'Hello world!'
].
[Foo new myMethod].

---
[(File open: 'test.dat' withPermissions: 'w') nextPutAll: 'Hello world!']

=============================


But perhaps more interesting is when we want to use module packaging,
namespace (scope) binding, and argument typing, as in the following script.

NOTE: Without all the numerous explanatory comments, the following code is
simple.
====================
module name=MyModule dll=Kernel32
{
    <!--
        Description: Within our module, override any <String> arg calls
                     to <File> #write(<>) or #puts(<>).

               Note: The subsequent 'module=MyModule' attribute is redundant
                     because it is implied by nesting a method for an
external
                     class within our (deployment packaging) module.
    -->
    method class=File scope=MyModule module=MyModule
    {                   "" ^- Scope limits visibility of this method
        ::write(<>)     "" <- declare an alternate name for this method
        puts(<String> aString)
            " ^- limits method binding to types of Strings"
            /*
                When we are invoked, log a message to stderr
                and then invoke the general version.
            */

           "Because we declared that our module act as a namespace for the
            Kernel32.DLL, via dll=, we can call any of its entry points
            without needing to declare them."

            | fileName | := String(MAX_FILE_PATH).
            fileName.size(GetModuleFileName(null,fileName,fileName.size)).

            "" Log the message here
            stderr << '`nWe just used a custom File::write(<>) version'.
                      ' from module: ' << fileName.

            "" Invoke the standard write routine here
            return self::File.write(aString)
            (*
                We could have qualified the #write message via these
                other forms:

                  self #File.write(...)
                  self #::File.write(...)
            *)
    }

    <!-- Now execute custom version -->
    {File('test.dat','w'.puts('Hello world!`n')}

    <!-- Now execute standard version because of type discrimination -->
    {File('test.dat','w'.puts(42)}
}

<!-- Now execute standard version because this eval/immediate method
     is outside the module scope -->
{File('test.dat','w'.puts('`nHello world!')}

====================

I intentionally used a wide variety of the different comment styles allowed
(there are additional forms including Unicode variants). The comment forms
also enable an extensible form of JavaDoc.

Normally, I would adopt one comment style and use it consistently.

I should also point out that, in general, the SmallScript parse tree
facilities enable an IDE or similar tool to rewrite/transform/present source
code into either of the various SmallScript and Smalltalk like styles that
were shown in these examples.

-- Dave S.

>
> Here, class Foo inherits from class Bar.  Except that class Bar is just an
> expression that returns a Class object.  In this case it's a constant, but
> you could just as easily have:
>
> class Foo < someMagicRoutine(someArgument, somethingElse)
>
> File is a real object, we'll call open on it.  The opened file object is
> passed to the block as local variable f, where we can call puts (named as
> in libc) to put a string to the file.  At the conclusion of the block,
> the file is closed automatically.
>
> Doesn't look much like Perl to me.  Oh, and that's just one way to
> use files -- you don't have to use them in a block, but I find it
> handy to make sure I've really closed a file :-)
>
>
> /\ndy
>
> --
> Andrew Hunt, The Pragmatic Programmers, LLC.
> Innovative Object-Oriented Software Development
> web:   http://www.pragmaticprogrammer.com   email:
andy / pragmaticprogrammer.com
> --
> Books by Andrew Hunt and David Thomas:
>     "The Pragmatic Programmer" (Addison-Wesley 2000)
>     "Programming Ruby" (Addison-Wesley 2001)
> --