unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Should `indirect-function' be preferred over `fboundp'?
@ 2023-07-20  7:08 Ihor Radchenko
  2023-07-20  7:42 ` Eli Zaretskii
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Ihor Radchenko @ 2023-07-20  7:08 UTC (permalink / raw)
  To: emacs-devel

Hi,

I have recently stumbled upon the common Elisp pattern
(when (fboundp func) (funcall func)) failing.

This is happening when a symbol is declared as function alias to
non-existing function:

(defalias 'yant/foo 'yant/bar)
(fboundp 'yant/foo) ; => t
(funcall 'yant/foo) ; => ERROR: Symbol function definition is void: yant/foo

In contrast, `indirect-function' does a better job determining whether a
given symbol can be called as a function:

(indirect-function 'yant/foo) ; => nil

Is it something widely known?
Is it something to worry about?
(I can see that `fboundp' is used all over Emacs git sources, while
`indirect-function' is rarely used)

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-20  7:08 Should `indirect-function' be preferred over `fboundp'? Ihor Radchenko
@ 2023-07-20  7:42 ` Eli Zaretskii
  2023-07-20  8:23   ` Ihor Radchenko
  2023-07-20  7:47 ` Andreas Schwab
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2023-07-20  7:42 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-devel

> From: Ihor Radchenko <yantar92@posteo.net>
> Date: Thu, 20 Jul 2023 07:08:48 +0000
> 
> (defalias 'yant/foo 'yant/bar)
> (fboundp 'yant/foo) ; => t
> (funcall 'yant/foo) ; => ERROR: Symbol function definition is void: yant/foo
> 
> In contrast, `indirect-function' does a better job determining whether a
> given symbol can be called as a function:
> 
> (indirect-function 'yant/foo) ; => nil
> 
> Is it something widely known?

The ELisp manual says:

 -- Function: fboundp symbol
     This function returns ‘t’ if the symbol has an object in its
     function cell, ‘nil’ otherwise.  It does not check that the object
     is a legitimate function.

So this is at least documented.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-20  7:08 Should `indirect-function' be preferred over `fboundp'? Ihor Radchenko
  2023-07-20  7:42 ` Eli Zaretskii
@ 2023-07-20  7:47 ` Andreas Schwab
  2023-07-20  8:25   ` Ihor Radchenko
  2023-07-20 13:02 ` Alan Mackenzie
  2023-07-21  1:08 ` Michael Heerdegen
  3 siblings, 1 reply; 12+ messages in thread
From: Andreas Schwab @ 2023-07-20  7:47 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-devel

On Jul 20 2023, Ihor Radchenko wrote:

> (I can see that `fboundp' is used all over Emacs git sources, while
> `indirect-function' is rarely used)

indirect-function used to signal an error when unbound.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-20  7:42 ` Eli Zaretskii
@ 2023-07-20  8:23   ` Ihor Radchenko
  0 siblings, 0 replies; 12+ messages in thread
From: Ihor Radchenko @ 2023-07-20  8:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> The ELisp manual says:
>
>  -- Function: fboundp symbol
>      This function returns ‘t’ if the symbol has an object in its
>      function cell, ‘nil’ otherwise.  It does not check that the object
>      is a legitimate function.
>
> So this is at least documented.

Yup, but docstring is a lot more deceiving.

    fboundp is a function defined in data.c.
    
    Signature
    (fboundp SYMBOL)
    
    Documentation
    Return t if SYMBOL's function definition is not void.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-20  7:47 ` Andreas Schwab
@ 2023-07-20  8:25   ` Ihor Radchenko
  0 siblings, 0 replies; 12+ messages in thread
From: Ihor Radchenko @ 2023-07-20  8:25 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: emacs-devel

Andreas Schwab <schwab@suse.de> writes:

> On Jul 20 2023, Ihor Radchenko wrote:
>
>> (I can see that `fboundp' is used all over Emacs git sources, while
>> `indirect-function' is rarely used)
>
> indirect-function used to signal an error when unbound.

AFAIU, it was very long time ago, before Emacs 26 at least. So, it is
now safe to assume that `indirect-function' can be used in place of
`fboundp' for most of the Emacs versions used in the wild.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-20  7:08 Should `indirect-function' be preferred over `fboundp'? Ihor Radchenko
  2023-07-20  7:42 ` Eli Zaretskii
  2023-07-20  7:47 ` Andreas Schwab
@ 2023-07-20 13:02 ` Alan Mackenzie
  2023-07-20 13:08   ` Ihor Radchenko
  2023-07-21  1:08 ` Michael Heerdegen
  3 siblings, 1 reply; 12+ messages in thread
From: Alan Mackenzie @ 2023-07-20 13:02 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-devel

Hello, Ihor.

On Thu, Jul 20, 2023 at 07:08:48 +0000, Ihor Radchenko wrote:
> Hi,

> I have recently stumbled upon the common Elisp pattern
> (when (fboundp func) (funcall func)) failing.

> This is happening when a symbol is declared as function alias to
> non-existing function:

> (defalias 'yant/foo 'yant/bar)
> (fboundp 'yant/foo) ; => t
> (funcall 'yant/foo) ; => ERROR: Symbol function definition is void: yant/foo

I don't think it affects the point you are making, but why are you using
funcall in the last line, rather than just calling the funcion as

  (yant/foo)

?  I initially got confused and thought you were doing

  (funcall yant/foo)

, which would have been an obvious error.

> In contrast, `indirect-function' does a better job determining whether a
> given symbol can be called as a function:

> (indirect-function 'yant/foo) ; => nil

> Is it something widely known?
> Is it something to worry about?
> (I can see that `fboundp' is used all over Emacs git sources, while
> `indirect-function' is rarely used)

> -- 
> Ihor Radchenko // yantar92,
> Org mode contributor,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <https://liberapay.com/yantar92>

-- 
Alan Mackenzie (Nuremberg, Germany).



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-20 13:02 ` Alan Mackenzie
@ 2023-07-20 13:08   ` Ihor Radchenko
  0 siblings, 0 replies; 12+ messages in thread
From: Ihor Radchenko @ 2023-07-20 13:08 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: emacs-devel

Alan Mackenzie <acm@muc.de> writes:

> I don't think it affects the point you are making, but why are you using
> funcall in the last line, rather than just calling the funcion as
>
>   (yant/foo)

I stumbled upon this behaviour in Org mode's code that works with src
blocks:

#+begin_src language
  <code>
#+end_src

Org uses heuristics to determine how to fontify such code blocks:

1. Org tries to derive the major mode name from language name
   constructing a symbol as (format "%s-mode" language)

2. If the symbol is a function, Org proceeds running that function to
   expedite fontification.

So, no, it would not be possible to write (language-mode) directly.
Function symbol string is calculated dynamically.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-20  7:08 Should `indirect-function' be preferred over `fboundp'? Ihor Radchenko
                   ` (2 preceding siblings ...)
  2023-07-20 13:02 ` Alan Mackenzie
@ 2023-07-21  1:08 ` Michael Heerdegen
  2023-07-21  6:07   ` Ihor Radchenko
  3 siblings, 1 reply; 12+ messages in thread
From: Michael Heerdegen @ 2023-07-21  1:08 UTC (permalink / raw)
  To: emacs-devel

Ihor Radchenko <yantar92@posteo.net> writes:

> (I can see that `fboundp' is used all over Emacs git sources, while
> `indirect-function' is rarely used)

I'm actually not that surprised.  I guess, most often code using an
`fboundp' test wants to test whether a function has already been defined
(e.g. by another package), or is available in the current Emacs version.

An alias is a definition.  In most cases the definition as an alias is
intentional.  If an alias points to an undefined function, I guess that,
in the majority of cases, this hints at some kind of problem so it's
better to have an error rather than to circumvent the problem by using
`indirect-function'.

Are aliases to undefined functions something to expect often?  The
compiler warns in the case when the DEFINITION is the name of an unknown
function.  It should be the responsibility of the alias creating code to
ensure that the alias is not broken.


Michael.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-21  1:08 ` Michael Heerdegen
@ 2023-07-21  6:07   ` Ihor Radchenko
  2023-07-22  2:49     ` Michael Heerdegen
  0 siblings, 1 reply; 12+ messages in thread
From: Ihor Radchenko @ 2023-07-21  6:07 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

Michael Heerdegen <michael_heerdegen@web.de> writes:

> An alias is a definition.  In most cases the definition as an alias is
> intentional.  If an alias points to an undefined function, I guess that,
> in the majority of cases, this hints at some kind of problem so it's
> better to have an error rather than to circumvent the problem by using
> `indirect-function'.

Fair point.

> Are aliases to undefined functions something to expect often?  The
> compiler warns in the case when the DEFINITION is the name of an unknown
> function.  It should be the responsibility of the alias creating code to
> ensure that the alias is not broken.

In my case, it was ob-lilypond.el aliasing a function in optional
dependency, although that is not a good style (I fixed that already).

Another possible scenarios is `define-obsolete-function-alias' when the
function is not loaded for some reason (like when it is defined in a
different file). We have plenty of these in org-compat.el.

Finally, user aliases defined in the user config, where accidentally not
loading some package is not unseen (especially with `use-package' and
friends that make it more forgiving to not have some packages
installed).

I think that part of the problem _for me_ is that

(defalias 'yant/foo 'yant/bar)
(fboundp 'yant/foo) ; => t
(funcall 'yant/foo) ; => ERROR: Symbol function definition is void: yant/foo

only shows an error for `yant/foo', which is somewhat confusing.
`yant/bar' is where function definition is truly void.

That's what took me some extra time to figure out what is wrong.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-21  6:07   ` Ihor Radchenko
@ 2023-07-22  2:49     ` Michael Heerdegen
  2023-07-22 10:51       ` Ihor Radchenko
  0 siblings, 1 reply; 12+ messages in thread
From: Michael Heerdegen @ 2023-07-22  2:49 UTC (permalink / raw)
  To: emacs-devel

Ihor Radchenko <yantar92@posteo.net> writes:

> Another possible scenarios is `define-obsolete-function-alias' when the
> function is not loaded for some reason (like when it is defined in a
> different file). We have plenty of these in org-compat.el.

> Finally, user aliases defined in the user config, where accidentally not
> loading some package is not unseen (especially with `use-package' and
> friends that make it more forgiving to not have some packages
> installed).

These examples still sound like mistakes to me.  One can either ensure
the library is loaded, or autoload the aliased function, or define the
alias only after the defining package is loaded (e.g. by using
`with-eval-after-load').

> I think that part of the problem _for me_ is that
>
> (defalias 'yant/foo 'yant/bar)
> (fboundp 'yant/foo) ; => t
> (funcall 'yant/foo) ; => ERROR: Symbol function definition is void: yant/foo
>
> only shows an error for `yant/foo', which is somewhat confusing.
> `yant/bar' is where function definition is truly void.

I see and understand.  The error message can be misleading in this case.

When something like this happens, I suggest to start investigating using
`symbol-function' instead of `fboundp'.

It's probably also preferable to function quote the existing function name
when possible, like in

  (defalias 'yant/foo #'yant/bar)


Michael.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-22  2:49     ` Michael Heerdegen
@ 2023-07-22 10:51       ` Ihor Radchenko
  2023-07-23  2:37         ` Michael Heerdegen
  0 siblings, 1 reply; 12+ messages in thread
From: Ihor Radchenko @ 2023-07-22 10:51 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

Michael Heerdegen <michael_heerdegen@web.de> writes:

>> I think that part of the problem _for me_ is that
>>
>> (defalias 'yant/foo 'yant/bar)
>> (fboundp 'yant/foo) ; => t
>> (funcall 'yant/foo) ; => ERROR: Symbol function definition is void: yant/foo
>>
>> only shows an error for `yant/foo', which is somewhat confusing.
>> `yant/bar' is where function definition is truly void.
>
> I see and understand.  The error message can be misleading in this case.

Would it be of interest to add 2 new error types:
1. Qvoid_indirect_function
2. Qinvalid_indirect_function

It will make it more explicit that it is function indirection that has
problems.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Should `indirect-function' be preferred over `fboundp'?
  2023-07-22 10:51       ` Ihor Radchenko
@ 2023-07-23  2:37         ` Michael Heerdegen
  0 siblings, 0 replies; 12+ messages in thread
From: Michael Heerdegen @ 2023-07-23  2:37 UTC (permalink / raw)
  To: emacs-devel

Ihor Radchenko <yantar92@posteo.net> writes:

> Would it be of interest to add 2 new error types:
> 1. Qvoid_indirect_function
> 2. Qinvalid_indirect_function
>
> It will make it more explicit that it is function indirection that has
> problems.

I think I can live without these, to be honest.  But let's hear other
opinions.

Michael.




^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-07-23  2:37 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-20  7:08 Should `indirect-function' be preferred over `fboundp'? Ihor Radchenko
2023-07-20  7:42 ` Eli Zaretskii
2023-07-20  8:23   ` Ihor Radchenko
2023-07-20  7:47 ` Andreas Schwab
2023-07-20  8:25   ` Ihor Radchenko
2023-07-20 13:02 ` Alan Mackenzie
2023-07-20 13:08   ` Ihor Radchenko
2023-07-21  1:08 ` Michael Heerdegen
2023-07-21  6:07   ` Ihor Radchenko
2023-07-22  2:49     ` Michael Heerdegen
2023-07-22 10:51       ` Ihor Radchenko
2023-07-23  2:37         ` Michael Heerdegen

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).