Hacker News new | past | comments | ask | show | jobs | submit login
Tips on Emacs Lisp programming (ferrier.me.uk)
59 points by nic-ferrier on July 29, 2012 | hide | past | favorite | 28 comments

It is weird to use CLOS with Emacs. First off, you don't get a real CLOS implementation, you only get superficially similar syntax. Many critical features are missing. Secondly, your users lose the ability to customize your package in ways you didn't design for. (In other disciplines of software engineering, you're writing software that must run unattended without error for years. In Emacs, you're writing software for a programmer sitting in front of your program. The engineering compromises to make, therefore, are significantly different.)

To do something like OO in Emacs, define variables that are buffer-local, and then use the buffer as the object.

Obviously I agree disagree, which is why I wrote it.

"Many critical features" - I disagree, it's good enough OOP, as capable as Javascript's for example.

Maybe you shouldn't consider it for a user mode or some such (though I don't see why, there are enough modes that do use it) but I made clear in my article that I was asking people to consider EmacsLisp as a real language in which you could write programs that are not just Emacs programs, scripts for example, which I specifically alluded to.

Web programming is also possible of course, with Elnode - http://elnode.org/

Just because you can hammer a square peg into a round hole doesn't mean you should. The primary use case for Emacs Lisp is for extending Emacs. At that task, it does a pretty good job. As a general-purpose programming language it's not horrible, but it's not great either. You'll be much more productive if you use one of the many excellent general-purpose programming languages for general-purpose programming. CL and Scheme, for example, are fine.

Emacs Lisp's flaws are forgivable when writing Emacs extensions because it integrates so well with Emacs. But without the Emacs integration, it's not that great.

Of course, I totally disagree with this, which is what the premise of the article was. EmacsLisp is now a general purpose programming language that I think competes well with Python or Ruby.

But of course, it's not suited to every application.

I'm still tickled by the fact that object oriented programming in elisp is just part of a standard library you can import.

This is why I think some Lisp (probably Scheme rather than elisp :P) is a great introductory language: very little is magical or built into the language itself. So you learn about things like OOP as patterns rather than as the one and only way to do stuff (cough Java cough).

That's the approach that SICP takes, and it works really well. Among other things, they show you how to make a basic object system.


And that's great. It's not so much fun for a working programmer though. You don't want to have to implement an object system over and over again, you want to use one to write code.

scheme is great for learning, but as I am trying to make clear with this series of posts on Elisp, there's no other Lisp that's as practical as Elisp, just because of the huge amount of code there is available. It's a fantastic learning resource that people should leverage.

Scheme is still a bit stuck in the multiple-implementations-none-of-which-fully-implement-exactly-what-you-want type stage.

EmacsLisp is like Ruby, but better. One implementation (basically all the others are gone) and lots of people hacking on it and making it better.

The ways it differs from Ruby are that it's a proper Lisp (macros and homoiconicity) and that all the development and debugging tools are built in. Edebug is a fantastic tool for example.

for me it's the casual way to import prolog that does it

> object oriented programming in elisp is just part of a standard library you can import.

This is how OO is done in Common Lisp (CLOS is the standard here) and Scheme (no standard object system, but every so often someone writes one for themselves).

My (perhaps limited) understanding is that in CL everything, including integers and similar basic types, is an object - nothing has to be boxed or unboxed, nor does one necessarily need to instantiate objects in order to use them. That's not to say that there are not objects similar to those of Blub made available through CLOS, only that as is typical, Lisp muddies the waters when using terms like "object oriented." $$

$$ Reading Let Over Lambda is what done it to me.

No, I don't think so. Behind the slightly odd syntax CLOS is a very traditional OOP system. In my example in the article there's even type checking in the method:

(defmethod some-user-greeting ((user some-userc) &optional daytime) ....)

means that the argument 'user' to the method MUST be an object of class 'some-userc'.

EmacsLisp's CLOS doesn't have as much type checking as CL's but it is there.

> in CL everything, including integers and similar basic types, is an object - nothing has to be boxed or unboxed, nor does one necessarily need to instantiate objects in order to use them.

This is what CL people say, certainly; what you think of this statement (true? useful? a bad definition of 'object'?) depends entirely on what you think an 'object' is.

If you're a Smalltalker (or a Java programmer, or a C++ programmer, or a user of any language that got its object system from Smalltalk), then an object is something that can respond to messages. CLOS doesn't work like this: There are no messages, and expressions don't contain objects privileged to be the recipient of the message being used; therefore, a Smalltalker might well say that while CLOS has inheritance and polymorphism, it doesn't have objects as such.

(And, off in the corner, some C programmers are insisting that an int is a perfectly good object.)

I think that argument is nonsensical (it's covered well on the CL wiki btw - http://c2.com/cgi/wiki?HowObjectOrientedIsClos ). CLOS clearly has messages (which are implemented with methods).

I wish I had more time to get better with emacs. I use it all the time and when I see things like this it makes me love emacs and hate that I don't take advantage of how deep it is.

Learn a little at a time. Don't compare your knowledge to other's or to the total amount possible, just to what you knew before. Keep it up and you'll slowly get better and better over time.

I also find it useful to keep a short file of features I want to learn and features (1 or 2) I'm currently learning (trying to use as much as possible even if it slows me down a bit so that they'll stick in my mind).

That's one of the reasons I wrote this. One thing you could do is write scripts in it. Or smaller programs.

One thing I'd really like to do is to make a massive index of emacs-lisp code on github. That would be a fantastic resource.

You mean like https://github.com/emacsmirror? :)

No, that's just a list of stuff (there are other really good pointers to elisp on github too) - I want an index of all the functions and variables used in the code there, hopefully with a usage index (where is find-file used?). It would be big data but totally awesome.

There is also a important lesson which goes like this: your scripts should operate on a buffer (even a temporary one) and almost never on strings. Its generally easier that way because there is so much support from all the functions already exposed to editing tasks.

Hmmm... I think I disagree with this as well... strings are very very well supported... it's a little annoying that we don't have a full string lib in elisp (some of the things here http://emacswiki.org/emacs/ElispCookbook#toc1 are missing, but that's why I say you can copy and paste when you need to).

You rather write something like this (from Emacswiki) operating on strings?

        (defun kill-whitespace ()
          "Kill the whitespace between two non-whitespace characters"
          (interactive "*")
                  (re-search-backward "[^ \t\r\n]" nil t)
                  (re-search-forward "[ \t\r\n]+" nil t)
                  (replace-match "" nil nil))))))

it depends on the context... but maybe replace-regexp-in-string would be the right function to use for strings in this context.

Of course, a lot of the time buffers are really powerful tools to replace strings. I just don't think your original assertion of "almost never" is right. Buffers are handy but I use them to replace strings less than 50% of the time.

Is it really the convention to name a some-user class 'some-userc'? Eeeargh -- I can see it's sort of like the established -p convention for predicates, but there at least it'd be 'some-user-p' instead.

It's not a widespread convention because use of OO is not massively widespread.

I agree stuff like this is ugly, but use of annoying naming conventions in order to get an extremely practical implementation language (particularly a Lisp) is a trade off I'm happy to make.

Since elisp allows it, I find '?' very elegant for predicates.

I agree, but foo-p doesn't make me go all "wtf?"

Applications are open for YC Winter 2021

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact