Org-mode mailing list
 help / color / mirror / Atom feed
* Multiple named code blocks
@ 2020-11-28 22:35 mooss
  2020-11-28 22:59 ` Tom Gillespie
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: mooss @ 2020-11-28 22:35 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 2967 bytes --]

Hi,

I have been using org-mode for almost three years and I loved it so much that I started working on a literate programming tool based on it.
One particular technique that I use is having multiple named code blocks, like so:

#+begin_src perl :noweb yes :results output
<<Before foo>>
sub foo {
<<In foo>>
}
foo;
#+end_src

#+name: Before foo
#+begin_src perl
print "Before foo definition.\n";
#+end_src

#+name: Before foo
#+begin_src perl
my $value = 'Inside foo call';
#+end_src

#+name: In foo
#+begin_src perl
print $value . "\n";
#+end_src

This technique worked without issue until I recently updated Emacs and org-mode with it.
I do not know the version of org-mode I was using before, but this was with Emacs 26.3 and I upgraded to Emacs 27.1 with org-mode 9.4 according to the information at the top of elpa/org-plus-contrib-20201116/org.el.

Before the update, the code block after expansion (obtained with org-babel-expand-src-block via the C-c C-v C-v shortcut) looked like this:
#+begin_src perl
print "Before foo definition.\n";
my $value = 'Inside foo call';
sub foo {
print $value . "\n";
}
foo;
#+end_src

Now the definition of $value is gone:
#+begin_src perl
print "Before foo definition.\n";
sub foo {
print $value . "\n";
}
foo;
#+end_src

I have looked at the info manual so I realise that according to "15.2 Structure of Code Blocks": "For duplicate names, Org mode’s behavior is undefined" so it follows that:
- Up until now, I was incorrectly assuming that duplicated named code blocks were supposed to result in them being concatenated in the noweb expansion phase.
- This is not a bug report, org-mode is working as documented.

I find this technique pretty useful for two reasons:
1. Importing packages right when they are needed.
2. Declaring variables in a broader scope than the one where they are first used.
Here is an short example of this kind of situation:

#+begin_src perl :noweb no
# Expansion of <<Variable declarations>>:
my $even_counter = 0;
my @array = (4, 8, 15, 16, 23, 42);
# A
# lot
# of
# other
# code
# [...]
foreach my $n (@array) {
# Expansion of <<Array processing>>:
$even_counter++ if $n % 2 == 0;
}
print "$even_counter";
#+end_src

In this example, $even_counter could not have been declared on the spot.
Of course, this example is too basic to really paint the usefulness of this technique but an actual example would be too long, the goal here is just to explain the general idea.

With all that being said I would suggest to define the behaviour for multiple named code blocks as resulting in a concatenation of the code blocks, in the order of their apparition.
If you agree about defining this behaviour but think adapting the implementation is of low priority, I could try to implement it myself though I have little experience in emacs-lisp development beyond basic configuration and no experience whatsoever in contributing to FOSS, but I'm willing to start in both domains.

Best regards,
Félix

[-- Attachment #2: Type: text/html, Size: 4673 bytes --]

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

* Re: Multiple named code blocks
  2020-11-28 22:35 Multiple named code blocks mooss
@ 2020-11-28 22:59 ` Tom Gillespie
  2020-11-29  0:40   ` mooss
  2020-11-29  3:24 ` Greg Minshall
  2020-11-29  8:28 ` Diego Zamboni
  2 siblings, 1 reply; 7+ messages in thread
From: Tom Gillespie @ 2020-11-28 22:59 UTC (permalink / raw)
  To: mooss; +Cc: emacs-orgmode

Hi Félix,
   I think that it is probably not a good idea to implicitly
concatenate blocks that share the same name. There are a number of
major downsides. One reason is that all the other parts of org-mode
assume that there is only a single block with that name, or rather
have undefined behavior if there is more than one, so all the other
reference resolving infrastructure will not work as expected and it
will be hard to navigate to additional blocks. The concatenation
behavior you describe does work if you specify the same file for
tangling, however that uses completely different code. Further, if we
were to define behavior for what should happen if there are multiple
blocks or sections with the same name it would probably either be to
signal an error (if you are in the more immutable camp), that the
first named block is the "canonical" block (current implementation),
or that the last defined block is the "canonical" block (if you want
org to be more like a programming language). The current
implementation follows the first named block, but the reason why the
manual states that it is undefined is because even that behavior
should not be relied upon (thus why an error is probably the most
friendly thing to do). Consider also that if you have different blocks
by the same name in different sections and you reorder the sections
the order in which they are nowebbed in will change. Given that that
behavior can be actively dangerous (imagine a block with cd
some-folder followed by a block rm contents/ -r getting reordered),
there are major downsides to trying to guess how to concatenate
multiple blocks and trying to specify restrictions on where and how
using the same name is allowed or can be safely used is not something
that anyone would want to try to do. Best!
Tom


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

* Re: Multiple named code blocks
  2020-11-28 22:59 ` Tom Gillespie
@ 2020-11-29  0:40   ` mooss
  0 siblings, 0 replies; 7+ messages in thread
From: mooss @ 2020-11-29  0:40 UTC (permalink / raw)
  To: Tom Gillespie; +Cc: emacs-orgmode

Hi Tom,

The downsides you mention are making perfect sense, especially
the cd and rm examples, I did not thought about that and I agree
that this would be a dangerous default.

Another possibility would be to shield this behaviour behind a
header argument, for example by adding a "dimension" to the
"noweb" argument.
What I mean by "dimension" is that to my knowledge, the header-
arg "noweb" only has a, let's say, "when" dimension that can take
one value among "yes" "no" and "no-export", whereas "results" can
have several dimensions, hence the validity of ":results drawer
replace" as a header-arg.
This new dimension could be called the "duplicated" dimension and
take values among "contatenate", "first" or "last".
With this scheme, one could use the header-arg ":noweb yes
concatenate" to always expand noweb inclusions and handle
multiple code blocks via concatenation.

I can see a couple of potential problems with this approach:
 1. It might be better to avoid adding header-args left and right
    to keep complexity in check and this feature is arguably
    quite niche.
 2. This would solidify the idea that multiple code blocks
    sharing the same name is good practice in org documents,
    which it is not, as you explained.

Yet another option would be to not rely on the names but on
another header-arg like "addto" that instruct the noweb resolver
to concatenate the current block to another named code block.
Reusing the previous example,

#+name: Before foo
#+begin_src perl
my $value = 'Inside foo call';
#+end_src

Would become:

#+begin_src perl :addto "Before foo"
my $value = 'Inside foo call';
#+end_src

Yet another approach would be to add a "directive" (that's probably not the right terminology), like so:

#+addto: Before foo
#+begin_src perl
my $value = 'Inside foo call';
#+end_src

The last two approaches would solve problem 2) but not problem
1).
There would also be the problem of what to do when a code block
is "added to" before its definition, what should be done ?
Throwing an error, appending or prepending ?

Personally I would prefer the last approach, even though the
prepending problem remains to be solved, because the other
approaches are polluting the header arguments and look out of
place there.
In any case, I think that a mechanism to concatenate to an
existing code block is a valuable feature for a literate
programming system.

On another note, that is a bit embarrassing but I'm not too sure
about how I am supposed to respond to this email list, I just
clicked on "Reply all" in my webmail client and this results in a
mail specifically addressed to you Tom and a CC to the list.
That is also what is suggested by the "Reply instructions:"
section of the list, but I just want to be sure that I am not
disrespecting a rule or custom that escapes me.

Best regards,
Félix


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

* Re: Multiple named code blocks
  2020-11-28 22:35 Multiple named code blocks mooss
  2020-11-28 22:59 ` Tom Gillespie
@ 2020-11-29  3:24 ` Greg Minshall
  2020-11-30 11:38   ` mooss
  2020-11-29  8:28 ` Diego Zamboni
  2 siblings, 1 reply; 7+ messages in thread
From: Greg Minshall @ 2020-11-29  3:24 UTC (permalink / raw)
  To: mooss; +Cc: emacs-orgmode

Félix,

i ran into this restriction a while ago.  on this list i was helped, and
ended up using the suggestion to instead put my common bits in a
property in the subtree for a given "name"

***** aggregate.R
       :PROPERTIES:
       :header-args+: :tangle build/package/covid.19.data/R/aggregate.R
       :header-args+: :noweb-ref aggregates
       :END:


then, the source blocks themselves have no name and are very plain

#+begin_src R


i don't know if that will be of any help.

cheers, Greg


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

* Re: Multiple named code blocks
  2020-11-28 22:35 Multiple named code blocks mooss
  2020-11-28 22:59 ` Tom Gillespie
  2020-11-29  3:24 ` Greg Minshall
@ 2020-11-29  8:28 ` Diego Zamboni
  2020-11-30 11:39   ` mooss
  2 siblings, 1 reply; 7+ messages in thread
From: Diego Zamboni @ 2020-11-29  8:28 UTC (permalink / raw)
  To: mooss; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 3586 bytes --]

Hi Felix,

You need to use the noweb-ref header argument instead of #+NAME, then the
block are all concatenated on output.

Best,
--Diego


On Sat, 28 Nov 2020 at 23:35, mooss <mooss@protonmail.com> wrote:

> Hi,
>
> I have been using org-mode for almost three years and I loved it so much
> that I started working on a literate programming tool based on it.
> One particular technique that I use is having multiple named code blocks,
> like so:
>
> #+begin_src perl :noweb yes :results output
> <<Before foo>>
> sub foo {
>     <<In foo>>
> }
> foo;
> #+end_src
>
> #+name: Before foo
> #+begin_src perl
> print "Before foo definition.\n";
> #+end_src
>
> #+name: Before foo
> #+begin_src perl
> my $value = 'Inside foo call';
> #+end_src
>
> #+name: In foo
> #+begin_src perl
> print $value . "\n";
> #+end_src
>
> This technique worked without issue until I recently updated Emacs and
> org-mode with it.
> I do not know the version of org-mode I was using before, but this was
> with Emacs 26.3 and I upgraded to Emacs 27.1 with org-mode 9.4 according to
> the information at the top of elpa/org-plus-contrib-20201116/org.el.
>
> Before the update, the code block after expansion (obtained with
> org-babel-expand-src-block via the C-c C-v C-v shortcut) looked like this:
> #+begin_src perl
> print "Before foo definition.\n";
> my $value = 'Inside foo call';
> sub foo {
>     print $value . "\n";
> }
> foo;
> #+end_src
>
> Now the definition of $value is gone:
> #+begin_src perl
> print "Before foo definition.\n";
> sub foo {
>     print $value . "\n";
> }
> foo;
> #+end_src
>
> I have looked at the info manual so I realise that according to "15.2
> Structure of Code Blocks": "For duplicate names, Org mode’s behavior is
> undefined" so it follows that:
> - Up until now, I was incorrectly assuming that duplicated named code
> blocks were supposed to result in them being concatenated in the noweb
> expansion phase.
> - This is not a bug report, org-mode is working as documented.
>
> I find this technique pretty useful for two reasons:
> 1. Importing packages right when they are needed.
> 2. Declaring variables in a broader scope than the one where they are
> first used.
>     Here is an short example of this kind of situation:
>
>     #+begin_src perl :noweb no
>     # Expansion of <<Variable declarations>>:
>     my $even_counter = 0;
>     my @array = (4, 8, 15, 16, 23, 42);
>     # A
>     # lot
>     # of
>     # other
>     # code
>     # [...]
>     foreach my $n (@array) {
>         # Expansion of <<Array processing>>:
>         $even_counter++ if $n % 2 == 0;
>     }
>     print "$even_counter";
>     #+end_src
>
>     In this example, $even_counter could not have been declared on the
> spot.
>     Of course, this example is too basic to really paint the usefulness of
> this technique but an actual example would be too long, the goal here is
> just to explain the general idea.
>
> With all that being said I would suggest to define the behaviour for
> multiple named code blocks as resulting in a concatenation of the code
> blocks, in the order of their apparition.
> If you agree about defining this behaviour but think adapting the
> implementation is of low priority, I could try to implement it myself
> though I have little experience in emacs-lisp development beyond basic
> configuration and no experience whatsoever in contributing to FOSS, but I'm
> willing to start in both domains.
>
> Best regards,
> Félix
>
>

[-- Attachment #2: Type: text/html, Size: 5107 bytes --]

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

* Re: Multiple named code blocks
  2020-11-29  3:24 ` Greg Minshall
@ 2020-11-30 11:38   ` mooss
  0 siblings, 0 replies; 7+ messages in thread
From: mooss @ 2020-11-30 11:38 UTC (permalink / raw)
  To: Greg Minshall; +Cc: emacs-orgmode

Hi Greg,

I don't know why I missed this, it is exactly what I needed.
Thank you for your help.

Best regards,
Félix


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

* Re: Multiple named code blocks
  2020-11-29  8:28 ` Diego Zamboni
@ 2020-11-30 11:39   ` mooss
  0 siblings, 0 replies; 7+ messages in thread
From: mooss @ 2020-11-30 11:39 UTC (permalink / raw)
  To: Diego Zamboni; +Cc: emacs-orgmode

Hi Diego,

This feature does indeed what I need, I will update my code with it.
Thank you for your help.

Best regards,
Félix


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

end of thread, other threads:[~2020-11-30 11:40 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-28 22:35 Multiple named code blocks mooss
2020-11-28 22:59 ` Tom Gillespie
2020-11-29  0:40   ` mooss
2020-11-29  3:24 ` Greg Minshall
2020-11-30 11:38   ` mooss
2020-11-29  8:28 ` Diego Zamboni
2020-11-30 11:39   ` mooss

Org-mode mailing list

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://orgmode.org/list/0 list/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 list list/ https://orgmode.org/list \
		emacs-orgmode@gnu.org
	public-inbox-index list

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.yhetil.org/yhetil.emacs.orgmode
	nntp://news.gmane.io/gmane.emacs.orgmode


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git