YAPC::Asia Tokyo 2013のPerl◯×クイズで、251文字までということを知ったので、なんで255文字でなく251文字なのかなと思ってちょっと調べた。
結論からいうと実装上の問題っぽい。でも、253文字にもできるんじゃないかなという気がした。
識別子の長さ制限がついたのは5.004からで、perl5004deltaのNew Diagnosticsに以下の記述がある。
Identifier too long
(F) Perl limits identifiers (names for variables, functions, etc.)
to 252 characters for simple names, somewhat more for compound
names (like $A::B). You've exceeded Perl's limits. Future
versions of Perl are likely to eliminate these arbitrary
limitations
というわけでperl5.004のtoke.c(字句解析器のソース)を読む。(最近のtoke.cも読んだんだけども古い方が読みやすい。メインのロジックはほぼ同じだし)
識別子をとってきている部分はscan_ident関数で
static char * scan_ident(s, send, dest, destlen, ck_uni) register char *s; register char *send; char *dest; STRLEN destlen; I32 ck_uni; { register char *d; register char *e; ... d = dest; e = d + destlen - 3; /* two-character token, ending NUL */ if (isDIGIT(*s)) { while (isDIGIT(*s)) { if (d >= e) croak(ident_too_long); // ここでIdentifier too longとなる *d++ = *s++; } } else { for (;;) { if (d >= e) croak(ident_too_long); // ここでIdentifier too longとなる if (isALNUM(*s)) *d++ = *s++; else if (*s == '\'' && isIDFIRST(s[1])) { *d++ = ':'; *d++ = ':'; s++; } else if (*s == ':' && s[1] == ':') { *d++ = *s++; *d++ = *s++; } else break; } } *d = '\0';
sは元の文字列でdestがトークンをコピーする先の文字配列を指すポインタ、destlenはコピー先の長さ。tokenのコピー先の配列の長さは256なんだけども、この関数を呼ぶ段階で既にsigilが入っていてdestは1バイト進み、destlenは255になっている。
if (d >= e) croak(ident_too_long); // ここでIdentifier too longとなる
となっているのだが、eは番兵みたいなもので、ここまでいってしまうとIdentifier too longをcroakする。
で、eは
e = d + destlen - 3; /* two-character token, ending NUL */
destlenは255で-3しているので252文字になった時にcroakすることになる。よって251文字までになる。
で、なんで-3しているかなのだけども、コメントにあるように1文字は文字列の最後のNUL文字用で、2文字はトークンの先読み用かなと。先読みというのは、先読み時に長さチェックしてからコピーするのではなく、コピーした後にe以上の位置になっていればcroakする。そのため、コピー先の配列が実際に許容する識別子の長さより長く必要となり、より手前でエラーにしてしまわないといけない。で、2文字としているのは、$a::bの::の部分を先読みして一度にコピーしているので2文字ということなのだろう。先に長さチェックしてコピーした方がわかりやすい気がするけども、perl5.004の頃なので性能とか考えたのかなと。
ただ、NUL文字は正常終了時にくっつけるだけじゃないのとか、'::'用に2文字余分にとっているのけど、'>='でeとの比較しているので1文字分は既に考慮されているんじゃないのとか考えると、253文字までいけそうな気がするんだけどね。