0

I want to set a variable to a function that is run every time the variable is used. Like Lazy set in a makefile

(setq counter 0)
(setq counter (+ 1 counter))
counter ; actual: 1 wanted: 1
counter ; actual: 1 wanted: 2
counter ; actual: 1 wanted: 3

How would i go about doing this? =)

  • 3
    The question isn't very clear (to me). For a start, why are you using (eval counter) instead of just counter - why the double evaluation? – Drew Mar 23 '18 at 17:11
  • 4
    This is a very oddly phrased question. It would make sense if elisp had such a feature (a variant of it is available via cl-symbol-macrolet), but it doesn't. Why would a newbie to the language ask for a very specific solution to a problem better solved in a different way? – wasamasa Mar 23 '18 at 20:55
  • 4
    The question is unclear - both what you want and why. Why do you want a variable counter here instead of a (nullary) function (counter)? – Drew Mar 27 '18 at 14:56
2

You seem to want the variable counter to hold two things at once: instructions to increment the counter, and the current value of the counter. You can't have both at the same time. There are a few programming languages where you can define “magic” variables that do something whenever they're read, but Emacs Lisp isn't one of them.

While you can store instructions to increment the counter in a variable and call eval to execute these instructions, this isn't the normal way to do things and I can't see any benefit to it. Instructions are normally stored in functions. You can use a variable to contain the current value of the counter, and a function to increment it and return the current value.

(defvar current-counter-value 0)
(defun (counter-next)
  "Increment the counter and return the new value."
  (setq current-counter-value (1+ current-counter-value)))
(print (counter-next))
(print (counter-next))
(print (counter-next))

This prints 1, 2, 3.

Lisp allows a function and a variable to have the same name, so you can name both counter if you want. But this can get confusing.

2

The effect that (eval counter) increments counter in some sense can be reached by setting counter to a quoted closure call. The eval evaluates the closure, the closure captures the actual counter and increments it at the eval. This solution does not address the setq part of your question. There follows example code together with usage instructions.

Put the following code into an elisp file (e.g., /tmp/test.el under Linux) and run emacs-lisp-byte-compile-and-load on that file (menu item Emacs Lisp > Byte-compile and Load).

;;; -*- lexical-binding: t -*-

(let ((counter_value 0))
  (defun counter-fun () (cl-incf counter_value)))

(defvar counter '(counter-fun))

Put (eval counter) into the *scratch* buffer and evaluate it. The first call gives 1 the second 2 and so on.

The code is tested with emacs-version 25.1.50.2.

Note, that it is even not necessary to put the incrementation of counter_value into a closure. You can also use (defvar counter_value 0) and the defun on top-level. Nevertheless the closure serves for information hiding. counter_value can only be accessed through counter in the version above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.