Destructuring Macro

Maybe my brain's just gotten too used to objects, but the idea of reaching into a structure and ripping out its guts seems kinda odd to me. When do you find it more useful (or intuitive or whatever) to destructure an object than to put the code inside the object itself? -- AdamSpitz (who might be confused about what "destructuring macro" means)

See http://www.bookshelf.jp/texi/onlisp/onlisp_8.html#SEC54. I think it pretty much speaks for itself; you want to use it practically whenever possible. -- DougMerritt (who might be confused about what you mean by "put the code inside the object itself")

So (taking my example right from that page) in Lisp, it seems like you might do something like this:

   (destructuring-bind ((first last) (month day year) . notes)
                               birthday
     ...)
In Self, I'd have a birthday object, and the birthday object would have three slots: "name", "date", and "notes". (And the name object would have "first" and "last" slots, and the date object would have "month", "day", and "year" slots.) I wouldn't need a "destructuring macro" to give names to the fields of the object; they'd already have names.

It's true, though, that it would be easier to construct a birthday "object" in Lisp than in Self, because in Self I'd have to say the name of each slot as well as the value that goes in it, whereas in the Lisp version I'd only have to say the values (but I'd have to know what position each value should go in).

What do you do, in Lisp, when you decide that you want to be able to represent people who have a middle name? It seems like you'd need to go around to all the places where you destructure a name and replace (first last) with (first middle last).

It also seems like the birthday-related functions wouldn't usually need to be aware that the name object consists of a "first" and "last" slot, or that a date object consists of a month and a day and a year. So maybe most of the time you wouldn't bother destructuring those parts - you'd just say:

   (destructuring-bind (name date . notes)
                           birthday
     ...)
And then it seems like you'd need to duplicate that call to destructuring-bind in all of your birthday-related functions. (So, of course, you make a macro for that. :)

Have I taken a wrong turn somewhere?

This just seems to me to be a really weird mindset - using a general-purpose data structure and then ripping the pieces out of it and giving them names, rather than using a data structure that knows the names of the pieces. And I'm not sure what it buys you. Can you give me an example of a use of one of these macros that wouldn't be just as easily done in an OO language? Right now all I can think of are examples like this:

   (defun distance-from-origin (aPoint)
      (destructuring-bind (x y) aPoint
         (square-root (+ (square x) (square y)))))
In the SelfLanguage, I'd write that as a method on the point object:

   distanceFromOrigin
     (x square + y square) squareRoot
I've got more questions, but this seems like a good time to stop and find out which parts of the Lisp mindset I've misunderstood. :)

-- AdamSpitz

Most of this was answered above, but there's the remaining question of why are Lispers fond of lists in contexts where in another language one would use an object. Well, Lisp does have objects, so people would sometimes use them instead.

But of course, any time you create a custom data structure, you have to create custom tools for manipulating that data structure, whereas when you use a generic data structure in any language, you can use all of the standard tools without needing to create new ones.

So in Lisp, it might well make sense to stick to lists and use standard list manipulations, including destructuring-bind, rather than creating a new birthday object and writing a custom destructuring-bind-to-birthday-object.

Whereas in other languages, possibly including Self, standard practice and idioms are such that one just assumes that one needs to do custom programming. (Nothing in Self that I am aware of prevents using a generic list, except that no one got around to creating destructuring-bind as a standard tool in Self.)

This was one of those things that got reinvented by so many people in Lisp over the years that it finally caught on as a standard. It seems to me one of the concepts that other languages should borrow.

-- DougMerritt

I often use destructuring-bind for conversion jobs when the data I have is not in the format I'd like it. Consider for example a (untested, mickey-mouse) HTTP server processing the request from a client:

(destructuring-bind (method url http-version)

    (split-sequence #\Space (read-line stream) :count 3)
  (make-instance 'http-request :method method :url url
                 :headers 
                 (if (> (mismatch request-version "HTTP/0") 6)
                     nil 
                     (read-headers stream))))

Within the domain of the application I'd tend to concur with Adam's original viewpoint; also I'd be using an object a la CLOS, not a naked list anyway, so destructuring-bind would be useless as well as inappropriate. -- DanielBarlow?, but feel free to refactor and remove sig

Saying you wouldn't use it if it were useless is beside the point. The question is, what would you do instead, to convert flat input data of some sort into the form that your nested birthday object needed? (E.g. would you create something akin to destructuring-bind that would work in your domain, or would you limp along without any utility functions to help, or what?)

I thought that was what Dan just said he would use destructuring-bind for. He wouldn't use it for internal application data, which is where objects would be handy. -- jt

His final paragraph says he'd use objects, and that destructuring-bind would then be useless.

I should have added that the chapter of "On Lisp" in question (see URL top of page) goes on to discuss generalizing the notion of destructuring-bind for non-lists, and then to more general patterns (using macros).

So although destructuring-bind is what the canned library offers, the point really is the concept behind it, which is a very handy one.

And yes, I'm basically suggesting that such a generalization can and should be used to populate the birthday object in question, so that indeed it doesn't deeply matter whether one is using lists or objects. -- dm


That makes sense to me. Thanks, guys.

My question now, though, is: How often does this problem come up in your world? I'm pretty sure I spend about 0% of my time converting flat input data into more useful forms, even though I definitely agree that Self is worse at it than Lisp is. Maybe the costs are just hidden? Or maybe my particular problem domain (VM and compiler stuff, these days) just naturally has very little flat user input? I dunno. Where are all of these flat input lists coming from, in your world?

-- AdamSpitz


I think that we're looking at two sides of the same coin. Consider a function in an OO language which takes a Ball object and computes its energy...

    double energy(object ball)
    {
        return 0.5 * ball.mass * ball.velocity^2;
    }

...compare and contrast to pattern matching against an algebraic data type Ball (a la Haskell)...

    energy (Ball mass velocity) = 0.5 * mass * velocity^2

Neither is better than the other, just different ways of accomplishing the task of naming pieces of data.

-- GregBuchholz?


See also: PatternMatching


EditText of this page (last edited November 26, 2014) or FindPage with title or text search