Mailing List Archive


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [tlug] Alternatives to sed + awk



Josh Glover writes:

 > > So *that* kind of "power" *subtracts* from expressiveness.
 > 
 > One use of Ruby's power tools that certainly adds to expressiveness is
 > defining a domain-specific language without needing a parser.

It is admittedly relatively hard to add syntax in Python.  However,
again it seems to me to be easy to abuse.  "Use in haste, repent at
leisure" seems to be the watchword of programmers.  And experience
shows that successful systems have decades of leisure for repentence;
experienced COBOL programers demand high salaries even today.

 > Lisp is also good for that, in fact most non-trivial Lisp systems
 > are built of one or more DSLs woven together (at least according to
 > Paul Graham and "The Scheme Programming Language"--I have no
 > experience writing production Lisp).

That's another way of expressing what I wrote:

 > > This is especially true of Lisp, where pretty much every large
 > > program is written in a language which shares the very basic "an
 > > expression is a list starting with a function and followed by
 > > expressions" syntax, but most expressions are functions with very
 > > specific requirements on the arguments, thus looking a lot like
 > > syntax.

However, the basic syntax of Lisp aka "Lots of Irritating Single
Parentheses" is detested by many.  Python takes the same approach:
using classes and methods it's possible to give objects many kinds of
behavior, but you mostly have to invoke them as function calls.
Whether you're willing to call that a DSL or not is a matter of taste,
I suppose.  Graham and I do.  Lots of people who program in Python
don't, so python-ideas gets a lot of proposals inspired by Ruby
features like "instance_eval".

 > > Adding methods to instances seems philosophically pointless.
 > 
 > It is quite useful for unit testing, when you don't add methods but
 > modify them. :)

Modifying methods can be done by subclassing.  However, Python's
approach is to decorate them:

# func must be nullary.  func with args is easy to handle but requires
# Python-specific syntax so I omit it.  Python 3: print is function.
def trace(func):
    if debug:
        def wrapped():
            print("Entering %s" % func.__name)
            result = func()
            print("Leaving %s" % func.__name)
            return result
        return wrapped
    else:
        return func

# This simple facility cannot be toggled at runtime.
# Rewriting trace can allow that at some cost in runtime efficiency.
debug = True
class Bruce(object):
    @trace
    def bruce(self):
        pass

The "@trace followed by def idiom" is equivalent to

    def bruce(self):
        pass
    self.bruce = trace(self.bruce)

(This is like Scheme, where a function identifier is one whose binding
is a function object, and the same identifier can't be used as a value
identifier without destroying the function binding, and unlike Lisp,
where identifiers have separate value and function bindings.)

BTW, since Ruby apparently allows you to omit parentheses, how do you
distinguish between returning the value of a function call and the function
itself, eg, in the argument to the trace invocation above?

 > > If you want to provide an operation on an instance, it seems to me
 > > that you either want to systematically create more similar instances,
 > > in which case you should subclass (or monkey-patch the class), or
 > > you don't, in which case use an ordinary function.
 > 
 > Or a lambda. :)

Explicit lambdas are something I've come to be less appreciative of
the longer I use Lisp.  The canonical example in Emacs is

(add-hook 'text-mode-hook (lambda () (auto-fill-mode 1)))

It turns out that it's much more convenient in the long run to do

(add-hook 'text-mode-hook (defun auto-fill-mode-on () (auto-fill-mode 1)))

because the latter call is idempotent (add-hook does nothing if the
value is already present, where "the value" means the same object; but
in the lambda version, the lambda expr is a new list each time the
add-hook expr is read, while the value of the defun is the function
symbol, and symbols are unique in the same Emacs process).

That means that you can reload the whole file containing the add-hook
without worrying about cluttering up your text-mode-hook.  (In this
case (auto-fill-mode 1) is itself idempotent, so no harm is done
except for clutter.  But you can imagine cases where non-idempotency
of a configuration action could lead to disaster, I'm sure.)

Of course, defun itself is just a macro that (among other things) does
the equivalent of

(put 'auto-fill-mode-on 'function-definition (lambda () (auto-fill-mode 1))

so there will always be *implicit* lambdas in Lisp.  Lisp also
provides flet (local function binding) and macrolet (local macro
binding), so you can avoid polluting the global or package namespace
if your intent is simply to refactor a single function.

 > def test_crappy_class
 >   crap = CrappyClass.new
 >   assert_equal 0, crap.instance_eval{@example.com
 >   crap.increment
 >   assert_equal 1, crap.instance_eval{@example.com
 > end

But, IIUC, in Python the member `value' is not hidden, so you just write

def test_crappy_class
    crap = CrappyClass.new
    assert_equal(0, crap.value)
    crap.increment()
    assert_equal(1, crap.value)

 > class_eval does the same thing, but on a class object. Rails uses
 > class_eval to provide accessors for model objects automatically based
 > on a database table layout, in some way that is roughly equivalent to
 > this:
 > 
 > tables.each do |table|
 >   columns = columns_for table
 >   columns.each do |column|
 >     table.to_class.class_eval "def #{column}; @#{column} end; def
 > #{column}=(val); @#{column} = val end"
 >     end
 >   end
 > end

That end" end end end looks like gdb. ;-)

I don't know how this is done in Python frameworks offhand, but
it is done somehow.

I see the attraction of the Ruby features for quick hacking, but I
also see the attraction of two-year-olds to swimming pools not
surrounded by fences.  The latter is a disaster; I hope you never
regret succumbing to the temptation of monkey-patching-supported-by-
syntax. ;-)

 > Right, Firefox is basically an application platform now. Except for
 > the C core, most of it is XUL and Javascript.

Thanks for the confirmation.

 > > It's not really obvious to me that any of the programs that Adamson
 > > mentions are actually written in C, anyway.  They're written in "Xt" or
 > > "GTK+" or "wxWidgets" or whatever.
 > 
 > That is an interesting view. I can't say that I disagree, which may
 > actually be a strength of C.  One wouldn't be able--IMO--to say the
 > same about a program written in Java, regardless of which widget
 > framework you were developing on. The Java-ness is just so
 > pervasive... *shudder* ;)

Well, the C-ness of an Xt program is pretty pervasive, too.  But C
does give nearly complete access to the instruction set, and a lot of
freedom in organizing your program.  So you don't feel as confined
when you write C as you do when you write Java.



Home | Main Index | Thread Index

Home Page Mailing List Linux and Japan TLUG Members Links