3 ms·
I'm not sure how much of our respective experiences is due to familiarity. For example, I have REPL power tools and a really good understanding of Ruby's object
by vinceguidry 8y ago
I'm not sure how much of our respective experiences is due to familiarity. For example, I have REPL power tools and a really good understanding of Ruby's object model to help me figure out what something's doing. So that almost never concerns me all that much.
Whenever I pull in a new gem, I usually budget a few minutes to wrap my head around the semantics of how the gem is expected to be used. Occasionally the documentation isn't good enough and I need to source dive.
What I never have to deal with is new syntax. No matter how Ruby is being used, the syntax is always the same comforting, pleasing-to-read near-prose. What changes when you use metaprogramming in Ruby is semantics. You can't add new syntax to the language unless you actually change the language.
Like you, I find people misusing metaprogramming. For me usually this is fairly easy to detect. If I look for the source of a method and it's dynamically generated, then showing the source will take me to where it was generated.
I won't pretend to have chosen Ruby over Lisp because I liked the language better. I chose it because I figured it would help me get a job better. But as time went on I found myself at home with Ruby.
I don't think it would take me all that long to get used to any given Lisp. But I don't believe it actually gives anyone superpowers, at least, not superpowers you can't have with Ruby. I have yet to hear a lisper actually articulate a solid advantage for code as data.
When there isn't any functional reason to choose between alternatives, all there's left is the aesthetic. Which is where all those parenthesis finally become important.
- taeric 8y agoHmm, you seem to be indicating that people use macros to create new syntax all of the time. I have not actually found that to be the case that often. In particular, there are only two macros I know I use somewhat regularly that do this. LOOP and FORMAT. And even those always follow the same general syntax of lisp. Unless you get crazy, it is not usual to actually use things that drastically change the full syntax of lisp. But again, in lisp, you probably make use of more metaprogramming than you'd realize, precisely because it is indistinguishable from normal programming. (I'm tempted to contrast this with some of the DSLs I've seen in the likes of scala and ruby... I have a hypothesis that all of the hoops you have to jump through to make a macro like construct cause people to go all in when they do so.) Now, I'm also not claiming lisp gives superpowers. Again, I'd almost go the other route. Most lisp is typically quite simple, because you can accomplish quite a lot that way. Which does bring it back to aesthetics some. The parens just flat out don't bother me. They are a bemusing joke, that never actually made sense. Too often, the difference is minimal compared to most C programs. Foo(bar) becomes (Foo bar). Which isn't that big of a deal. The basic math changes from infix to prefix is a bit to get used to. However, I find it is much more pleasant to deal with generics (+ matrix1 matrix2) as opposed to matrix1.plus(matrix2) of java and the like. Of course, I was also a huge fan of my HP calculator in college. RPN for the win! :) So, yes, I do think it comes down to preference. I don't think you're preference is wrong/bad. I do think your view of lisp sounds colored more by bemusing jokes than actual problems in lisp code. But, I fully grant my experience with ruby may be colored by an overly ambitious project written in it.
- vinceguidry 8y ago> (I'm tempted to contrast this with some of the DSLs I've seen in the likes of scala and ruby... I have a hypothesis that all of the hoops you have to jump through to make a macro like construct cause people to go all in when they do so.) I don't think we have any points of contention left to argue over, but I will say that many Rubyists just aren't familiar enough with Ruby's object model and scoping to be able to do DSLs cleanly. It's certainly possible, but there's a learning curve. Actually I can articulate how to do DSLs in a paragraph. Create a DSL class where all instance methods are DSL calls that set instance variables. The instantiator takes a block, the DSL input, and simply runs instance_exec on the block so it's executed in instance scope. Hand the DSL object with all the ivars to something else to actually do things with. Nothing in DSL behavior should do anything other than set ivars. The only metaprogramming is instance_exec.
- taeric 8y agoApologies if you took my posts as trying to argue you out of a position. I think the developer happiness is a fairly important point. And aesthetics being what they are, different strokes for different folks. So, I was just chiming in that I have an amusingly contrasted experience. To that end, thanks for keeping the discussion going! This is a social site, so it is fun to flat out be social. :)
- vinceguidry 8y agoOh I certainly don't see you doing that, that was why I said "I don't think we have any points of contention left to argue over." It's rather unfortunate that in a textual medium, tone must be inferred from prose. I just wanted to add a bit of extra color.
- kazinator 8y agoIn ANSI CL, the macro related to formatting is called formatter; format is just a function. The format function can take a function as an argument in place of the format string. The formatter macro can compile a format string into such a function. (format nil (formatter "(~a-~a)") x y) formatter spits out a lambda that is passed to format; format then passes it the stream, and the remaining arguments.