Vladimir -- writing the below made me think of whether we should
Hi David,Parenscript does have such an operator, called BIND. Since it hasn'tbeen documented yet, here are some examples. The idea is that you usekeywords to bind to object properties and ordinary symbols to bind toarray elements. Let's look at arrays first. A simple example:(bind (a b c) '(10 20 30)(list c b a))=> (30 20 10)Bind elements to NIL to ignore them:(bind (a nil c) '(10 20 30)(list c a))=> (30 10)To ignore the tail of an array, just omit it:(bind (a b) '(10 20 30 40)(list b a))=> (20 10)You can use &rest (or .) in the destructuring list:(bind (a &rest others) '(10 20 30)(list others a))=> ((20 30) 10)(bind (a . others) '(10 20 30)(list others a))=> sameYou can nest array bindings:(bind (a (b (c d)))'(10 (20 (30 40)))(list d c b a))=> (40 30 20 10)Now for objects. A simple example:(bind (:a :b :c) (create :a 10 :b 20 :c 30)(list c b a))=> (30 20 10)Since the properties are named, order doesn't matter:(bind (:a :c :b) (create :a 10 :b 20 :c 30)(list c b a))=> (30 20 10)If you want to bind to a property using a different name, you can usea binding pair instead of a keyword:(bind ((my-name :original)) (create :original 10)(list my-name))=> (10)I use that sparingly because the extra parens can impedereadability, but it's handy to avoid naming collisions:(let ((original 99))(bind ((mine :original)) (create :original 10)(list original mine)))=> (99 10)You can bind to an object inside an array:(bind (a (:b)) (list 10 (create :b 20))(list b a))=> (20 10)However, you can't bind to an array inside an object, or an objectinside an object, in a single BIND form — you have to use two:(bind (:a) (make :a '(10 20 30))(bind (nil b c) a(list c b)))=> (30 20)(bind (:a) (make :a (make :b 20 :c 30))(bind (:b :c) a(list c b)))=> (30 20)That's because the notation doesn't seem to allow for any unambiguousway to do such nesting. (If you can think of one, please show us someexamples.) This is the chief difference from the notation in yourexample, which adds additional syntax to support more complexdestructuring lists. The tradeoff here is that BIND, lacking syntax,handles the simplest and most common cases more elegantly.There is a form BIND* which allows multiple binds in a row to avoidunwanted indentation:(bind* ((a b) '(10 20)(:c) (make :c 30))(list a b c))=> (10 20 30)It simply takes a list of binding pairs and turns them into a nestedseries of BIND forms.Finally, note that if you mix keyword and non-keyword symbols in abinding list, it's considered an array binding and not an objectbinding:(bind (:a b) '(10 20)(list b a))=> (20 10)(bind (:a b) (make :a 10 :b 20)(list b a))=> (undefined undefined)But it's bad practice to mix keywords and non-keywords inthe same binding list. Perhaps BIND should throw an errorwhen given such input.So now let's look at your example:(d-bind (:obj name (:obj firstname lastname)likes (:arr first-like second-like))(create :name (create :firstname "Joe" :lastname "Blo"):occupation "Web Developer":likes '("programming" "woodworking" "cycling"))(alert (+ "Your name is " firstname " and you like " first-like)))As I mentioned, the main difference is that PS's BIND doesn't usespecial syntax like :obj and :arr to convey what's being destructured.No doubt tastes will differ on this. In any case, to translate yourexample, we'll have to use nested BINDs:(bind (:name :likes)(create :name (create :firstname "Joe" :lastname "Blo"):occupation "Web Developer":likes '("programming" "woodworking" "cycling"))(bind (:firstname) name(bind (first-like) likes(+ "Your name is " firstname " and you like " first-like))))=> "Your name is Joe and you like programming"We can do the same thing with BIND* like this:(bind* ((:name :likes) (create :name (create :firstname "Joe" :lastname "Blo"):occupation "Web Developer":likes '("programming" "woodworking" "cycling"))(:firstname) name(first-like) likes)(+ "Your name is " firstname " and you like " first-like))=> "Your name is Joe and you like programming"It would be a straightforward exercise to write your D-BIND as a macrothat interprets the :obj and :arr directives, uses gensyms to createintermediate bindings, and emits the above nested BIND form.If you find anything else in CoffeeScript that you think would be anatural fit for PS, please post it here.Daniel