3

A lot of emacs configurations shared publicly have this format:

;; 01-something.el
(provide 'something)

;; init.el
(require 'something)

Suppose I'm writing a defun named "s-join" inside 01-something.el

Suppose somewhere during init.el initialization, magit.el loads up s.el - the popular string utility package, which also has a defun named "s-join"

So now, in any given context, how do I know what gets executed when I do

(s-join)

?

Drew
  • 75,699
  • 9
  • 109
  • 225
american-ninja-warrior
  • 3,773
  • 2
  • 21
  • 40

3 Answers3

5

All functions and variables defined in a file that gets loaded are put into the global environment. Although Emacs has installable packages, those packages are not isolated from each other in any way. If two files define functions or variables with the same name then you'll get a warning when the second one is loaded.

You can find out where a function was defined by asking for help on the function with C-h f. It will prompt you for a function name. If the text at point looks like a valid lisp identifier, and a function by that name exists, that identifier will be the default value for the prompt. C-h v will do the same for variables. C-h F prompts for a function name and takes you to the info page where that function is documented, which may include more detailed information.

db48x
  • 15,741
  • 1
  • 19
  • 23
  • I’m a vim guy, but I thought emacs got lexical scoping at one point; wouldn’t this obviate some of that? – D. Ben Knoble Oct 08 '20 at 00:09
  • 1
    Emacs implements both lexical and dynamic scoping, but that's for the code inside of functions. Function and variable definitions happen in the global environment. – db48x Oct 08 '20 at 02:31
  • how do I ensure my function named "s-join" does not clash with the function of the same name from the s.el package – american-ninja-warrior Oct 10 '20 at 14:38
  • 2
    Simply use a name not currently used by any other package. The convention is that every package should start the name of every function with the package name. Thus package foo will define functions `foo-frob-the-thing` and `foo-compute-barness`, while package bar will define functions like `bar-frob-the-other-thing` and so on. For functions you define in your init file, you might consider using your own name as the prefix. For example, I have a function called `db48x/erc-generate-log-file-name-long-date` in mine, because that seemed like a good name at the time. – db48x Oct 10 '20 at 14:44
1

In Elisp, all functions names normaly (but not necessarily) reside as an entry in a global environment (obarray). In Elisp functions can be redefined. Which means the function definition which has been evaled (or loaded) last will be the only one, which is known and used.

This way you can change functions in your init file, you just need to be sure your function definition is evaled after the function you want to change.

But beware! If the original function changes in behavior or parameters, yours is not changing automatic, and so dependend functions could fail or misbehave.


Replying to those comments below, on how to avoid failure of using source code.

  1. you should choose a function name which is unique to your own function to prevent this (i.e. prefix your function name)
  2. you could write a guard around your function, to prevent your function definition overwriting some existing function (this does not help if your function gets overwritten, see next point)
(unless (fboundp 's-join)
  (defun s-join ()
    ...))
  1. you could use an advice at your function, and there check for characteristics of your function (i.e. parameters, or first sexp in body, etc.) IMO advices stay put even when the function gets redefined.
jue
  • 4,476
  • 8
  • 20
1

OP seems to be missing the point already clearly made in the two answers given: you cannot do what you are asking. Emacs uses a voluntary naming convention, not syntax or compilation rules, to define namespaces. It may sound like a recipe for chaos, but in practice it works very well.

What you are doing when you name your function s-join is (effectively) stealing the s package's namespace-identifying prefix, in breach of the convention. Don't do that. Name your function anw/join-strings or similar, as suggested above.

If you really, really need to temporarily replace an existing function, you can use cl-flet or cl-labels. See the Info node for the CL package.

Phil Hudson
  • 1,651
  • 10
  • 13