LATEX-L Archives

Mailing list for the LaTeX3 project

LATEX-L@LISTSERV.UNI-HEIDELBERG.DE

Options: Use Classic View

Use Monospaced Font
Show Text Part by Default
Condense Mail Headers

Topic: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Sender: Mailing list for the LaTeX3 project <[log in to unmask]>
Date: Tue, 16 Jul 2013 21:09:02 +0200
Reply-To: Mailing list for the LaTeX3 project <[log in to unmask]>
Message-ID: <[log in to unmask]>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
In-Reply-To: <[log in to unmask]>
Content-Type: text/plain; charset=windows-1252
From: Michiel Helvensteijn <[log in to unmask]>
Parts/Attachments: text/plain (147 lines)
On Tue, Jul 16, 2013 at 7:25 PM, Bruno Le Floch <[log in to unmask]> wrote:

> It is indeed useful to have unique csnames generated automatically.
> However, the need is sufficiently rare that it does not warrant adding
> a new variant letter:

I can understand that — if there are reasonable alternatives.

I would, however, like to dissect your reasoning a bit if you don't
mind — not to press my idea forward (though I know I have a tendency
to give that impression) but to better understand your considerations.

> this is expensive, since each function would
> need a new variant, hence a new entry in TeX's hash table, and this
> adds up pretty quickly to a very large number of csnames spent,
> slowing TeX down.

I don't see why every function should be pre-generated with a :U
variant. In fact, I would suggest that the programmer be forced to
generate, for himself, all the :U variants that he needs, because its
use will indeed be relatively rare.

> The proposed 'U' argument type would be altering the variable
> appearing as the corresponding argument, which is quite contrary to
> anything that any other argument type does.

That, in and of itself, is never a convincing argument to me. The
principle of least surprise sometimes has to be sacrificed to add
useful features or solve problems.

And in this case it's not even that much surprise. The existing
argument-types already have fundamentally different behaviors:
*  :c and :v turn a csname into a cs,
*  :x makes a function unexandable,
*  :p has one very specific use-case;
*  :w can basically do anything;
*  :D may not be used at all (but is still in the interface documentation);
*  :T and :F are just for show.

This is not meant negatively. I'm just saying that by comparison, :U
would not be all that shocking.

> Indeed, \unique_csname:N has no way to know when a given
> unique name is not used anymore.  This means that every time
> the map_inline function is called, a new unique csname is used.
> TeX will run out of hash table space relatively fast

A very good point.

>     \cs_new_protected:Nn \something_map_inline:Nn {
>         \unique_csname:n {
>             \cs_set:cpn {##1} ####1####2 {#2}
>             \something_map_function:Nc #1 {##1}
>         }
>     }

This looks familiar. In anticipation of your question at the end of
the mail: this is a very specific case of what my `\with` command
does. It's basically a one-shot anonymous-function-body — with
arbitrary argument-types — which is called immediately. It allows you
to "turn values into #-arguments" by beta-reduction.

>     \cs_new_protected:Nn \something_map_inline:Nn {
>         \unique_csname:n {
>             \cs_set:cpn { \l_unique_tl } ##1##2 {#2}
>             \something_map_function:Nc #1 { \l_unique_tl }
>         }
>     }
>
> The first one is a bit confusing since # does not need doubling, but
> ## does become ####.

Actually, the user of `\something_map_inline:Nn` will now need to
double all their #s. I've run into this problem myself, and the
solution is to let #2 pass through \unique_csname too, unaltered, then
use it as ##2. (See below for my `\with` solution.)

> The second one is a bit risky since one can only
> use \l_unique_tl before any other \unique_csname:n is called: here it
> is safe because \cs_set:cpn does not use \unique_csname:n.

This is exactly the kind of risk I wanted to mitigate with `\with`.
Though it has other uses.

> In fact, perhaps the right approach is that I revive some ideas I had
> about objects.  Mapping a function then amounts to repeatedly popping
> the first item and acting with the function.  I roughly see how to
> write a wrapper for that, which would mean that the package writer
> would not need to worry about defining the mapping function: rather he
> would define a \something_get:N or \something_pop:NN function, and the
> framework would do the work of defining map_function and map_inline.
> This is a longer term idea.

This would be a very useful contribution. Anything to auto-generate
all three mapping functions (including _map_tokens) from a simple
description.

> In any case, most of the above concerns specifically the application
> of your idea to defining map_inline.  If you have more examples where
> unique identifiers are useful, it would be very helpful to give them,
> so as to either find alternatives or get a better view of what would
> be needed.

Generally, any situation where an unbounded number of separate
internal macros are needed without the API user providing names for
them. I use it for `\with`. I use it for my ":r pointers".

> Can you give a short example of use of that package? I'm curious, and
> slightly too lazy to figure out the code. :-)

I don't want you to read the code right now anyway. ;-) It doesn't
exactly follow LaTeX3 guidelines yet.

To give you some examples of its use, here's a simple one, used to
force some specific expansion on a value buried deep inside an
expression:

\with:Vn \l_variable_tl {
    \bla:n { \do_not_expand_me bla bla bla #1 bla bla }
}

Here's how I currently implement my `\something_map_inline`s. I use
the non-expl3 version of `\with`, because expl3 doesn't have :U.

\cs_new_protected:Nn \something_map_inline:Nn {
    \with {Unn} [map_inline] [#2] {
        \cs_set:cpn {##1} ####1####2 {##2}
        \something_map_function:NN #1 {##1}
    }
}

The argument I give to the :U here is just some description which is
added to the csname, for debugging purposes.

Finally, here's how I create a new pointer with an initialized value:

\cs_new_protected:Nn \ptr_new:Nn {
    \with{u} [ptr] [#2] {
        \tl_set:Nn #1 {##1}
        \tl_new:c     {##1}
        \tl_set:cn    {##1} {##2}
    }
}

--
www.mhelvens.net

ATOM RSS1 RSS2