Let me quote the final paragraph of section 3.1 in interface3.pdf:
Finally, the functions in Subsections 3.2 and 3.3 are primarily meant to define base functions only. Base functions can only have the following argument specifiers:
N and n No manipulation.
T and F Functionally equivalent to n (you are actually encouraged to use the family of \prg_new_conditional: functions described in Section 1).
p and w These are special cases.
The \cs_new: functions below (and friends) do not stop you from using other argument specifiers in your function names, but they do not handle expansion for you. You should define the base function and then use \cs_generate_variant:Nn to generate custom variants as described in Section 2.
Here's what section 2 says:
\cs_generate_variant:Nn ⟨parent control sequence⟩ {⟨variant argument specifiers⟩}
This function is used to define argument-specifier variants of the ⟨parent control sequence⟩ for LaTeX3 code-level macros. The ⟨parent control sequence⟩ is first separated into the ⟨base name⟩ and ⟨original argument specifier⟩. The comma-separated list of ⟨variant argument specifiers⟩ is then used to define variants of the ⟨original argument specifier⟩ where these are not already defined. For each ⟨variant⟩ given, a function is created which will expand its arguments as detailed and pass them to the ⟨parent control sequence⟩.
There's no magic involved. When you say \cs_new_protected:Nn, you're using \def or \gdef in disguise. While it could be possible, in principle, to examine the given signature and define the function with the suitable expansion mechanism, it's undoubtedly better to go step by step:
\cs_new_protected:Nn \__a_one:n
{
...
}
\cs_generate_variant:Nn \__a_one:n { o }
because the \__a_one:n function would have to be defined anyway. So there's no point in setting up a complicated mechanism for this.
To be more specific, after that code, the meaning of \__a_one:o would be
\exp_args:No \__a_one:n
There would be no other practical way for a hypothetical \cs_new_protected:Nn \__a_one:o handling the required expansion to basically define \__a_one:n under the hood and then applying \cs_generate_variant:Nn.
My experience says that this is good: you always know what functions you have available, because you define all of them.
ntype argument and then define a variant with\cs_generate_variant:Nn. The typeso,V,x,v, orcall should be defined in terms of variants ofnorNtype arguments and never directly. – cgnieder Jan 04 '15 at 23:36\cs_new:Npnand friends you can define only functions havingn,N(orw) in their signature, because they are essentially\def(or similar) in disguise. Other argument types must be introduced with\cs_generate_variant:Nn– egreg Jan 05 '15 at 00:16\cs_new_protected:Npn \__a_one:oif, for instance, you use\tl_set:No \__a_tmp_tl {#1}inside of it. – Manuel Jan 05 '15 at 00:20norN. – egreg Jan 05 '15 at 00:23\cs_…:Npninstead of\cs_…:Nn. In case is that, then it was a mistake of mine, in case it wasn't, I don't know what you mean. – Manuel Jan 05 '15 at 00:25ofor a function defined with\cs_new:Npnor\cs_new:Nnand friends. – egreg Jan 05 '15 at 00:26\cs_new:Npn \foo:o { \tl_set:No \l_tmpa_tl }or something similar, I know it's not the best, but is it *that* bad? – Manuel Jan 05 '15 at 00:39\foo:owould be\l_tmpa_tlwhich instead is of typeN. Period. – egreg Jan 05 '15 at 00:43\l_tmpa_tlbecause it's in the definition. In any case, I agree with you in “you always know what functions you have available, because you define all of them”. – Manuel Jan 05 '15 at 00:45