3

I just discovered that it is possible to define strings with text properties using the special read syntax. Now I'm trying to evaluate a value of a property within the string definition so something like this:

#("Example" 0 1
  (:some-prop
   "something"
   :some-other-prop
   (concat "how to eval concat "
           "here?")))

would become:

#("Example" 0 1
  (:some-prop
   "something"
   :some-other-prop
   "how to eval concat here?")))

I could not figure it out. I know I could use put-text-property but maybe there is some backquoting technique or something else I could use instead?

2

I think it's sort of possible in some cases, but not out of the box.

Spoiler alert : I did not write any code, sorry!

Roughly, when you're going to evaluate some lisp (e.g. from a buffer), three things happen:

  • Reading, which converts the buffer content into Lisp objects
  • Macro-expansion
  • Evaluation

(Macro-expansion implies some evaluation, so it's not a clear

The #() construction happens when reading, while the backtick construction is a macro which does most of its job during macro expansion.

So we could try to surround the string literal with a backtick-like macro that will evaluate things during its expansion phase. Unfortunately the existing backtick will not dissect a string (it will only dissect a list or a vector, see the function backquote-process for more on this), so you would have to write the code yourself.

Another problem is that once a string literal was read, there's no guarantee that we can recover how properties were actually written within the literal. Consider the following:

#("foo" 0 3 (bar baz) 1 2 nil)

It is equivalent to:

#("foo" 0 1 (bar baz) 2 3 (bar baz))

How de we tell them apart ? We can't, they are equal-including-properties.

So now we already must impose conditions on what the string literal can contain, and even though this can be considered ok, it isn't super nice either.

Now let's look at another example:

#("foo" 0 2 (bar baz))

and

#("foo" 0 1 (bar baz) 1 2 (bar baz))

Again these two strings are equal-including-properties, so again it's not guaranteed that we can tell them apart from elisp [Side note: the lisp reader does not seem to "simplify" the first version to the second version in my current emacs, but that's lightly tested and not future-proof.]

Of course we can pretend these problems do not exist, but if baz is in fact code to be evaluated, that code might get evaluated once (first version) or twice (second version) depending on how we access the properties. Now that's pretty bad in my opinion.

Given the above, I now believe that implementing such a macro would be wasted effort.

  • s/backtick-process/backquote-process/? – npostavs Aug 17 '17 at 10:31
1

What do you mean by "evaluate" it? It's already a literal string, with some text properties. It evaluates to itself.

I suspect you are not being clear about what you are trying to do. What you are asking is how to evaluate a literal string - no different from asking how to evaluate the (property-less) string "abc".

If you are asking how to add properties to an existing string then the answer is, as you suggested: use put-text-property, set-text-properties, or add-text-properties.


UPDATE after you edited question:

#("Example" 0 1
  (:some-prop
   "something"
   :some-other-prop
   (concat "how to eval concat " "here?")))

You apparently have a string with text property :some-other-prop, whose value is the list (concat "how to eval concat " "here?"). And you want to replace that value of the property by its evaluation, i.e., interpreting concat as a function etc.

For that:

  1. Get the current value of the property.

  2. Evaluate it, to get the new value you want to replace it with.

  3. Put that new value back on the string as the updated property value.

Something like this:

(let* ((strg  #("Example" 0 1
                (:some-prop
                 "something"
                 :some-other-prop
                 (concat "how to eval concat " "here?"))))
       (val   (get-text-property 0 :some-other-prop strg)))
  (put-text-property 0 1 :some-other-prop (eval val) strg)
  strg)
  • I edited the question and tried to make it more clear. – clemera Aug 17 '17 at 6:53
  • The way your answered the question makes me feel that I may miss some underlying concept here and it's just not possible. – clemera Aug 17 '17 at 7:03
  • I don't know what you may be missing or how you understand my answer or what it is in "it's just not possible". It's not clear what you are trying to do - what you mean by evaluate that string. If you evaluate a string you get the same string; if you evaluate a number you get the same number, etc. A guess is that you want to add text properties to a string that has none. For that, you use the functions I listed. The string that you show already has text properties. – Drew Aug 17 '17 at 14:03
  • Have you looked at my edited version of the question? It should be clear now what I wanted to achieve. – clemera Aug 17 '17 at 14:06
  • 1
    Emacs Lisp, unlike Common Lisp, doesn't really give you much access to the Lisp reader. – Drew Aug 17 '17 at 14:31

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.