Feature #18573
openObject#pack1
Description
概要¶
String#unpack1 の逆の Object#pack1 が欲しい。
背景¶
Array#pack というメソッドがありますが、レシーバーの Array の要素数が 1 つしかないことが良くあります。
[codepoint].pack('U')
[digest].pack('m0')
[mail_body].pack('M')
[ip_address].pack('N')
標準添付ライブラリーなどを眺めてみてもチラホラあるようです。
ですが、このようなケースで変換対象のオブジェクトをわざわざ Array でくるまなくてはいけないというのは面倒な気もします。
提案¶
String#unpack に対して String#unpack1 というメソッドがありますが、
Array#pack に対する Object#pack1 というメソッドを提案します。
イメージとしては以下のコードのような感じです。
class Object
  def pack1(template, option = {})
    [self].pack(template, **option)
  end
end
議論・課題¶
- Object で良いかどうかは議論の余地があろうかと思います
- メソッド名が pack1 で良いかはわかりませんが、他とかぶる可能性は低いかと思います
        
           Updated by knu (Akinori MUSHA) over 3 years ago
          Updated by knu (Akinori MUSHA) over 3 years ago
          
          
        
        
      
      packしたいもの(のclass)はすごく限定的なので、Objectに生やすのはどうかなあと思いました。
        
           Updated by knu (Akinori MUSHA) over 3 years ago
          Updated by knu (Akinori MUSHA) over 3 years ago
          
          
        
        
      
      String#format / String#% のような感じで書式の方をレシーバにする方がよさそうですが、unpackとの対称性を考えると名前が難しいかも。
        
           Updated by knu (Akinori MUSHA) over 3 years ago
          Updated by knu (Akinori MUSHA) over 3 years ago
          
          
        
        
      
      今日のOffice Hourで話したんですが、レシーバごとにそれにふさわしい書式って限定されるはずなので、何でも屋のpackではなく、たとえばIntegerならビット幅とエンディアンを指定してバイナリ表現を得るメソッド、StringならNUL-terminatedなバイナリを得るメソッド、などをそれぞれ用意すべきかも、と思いました。
        
           Updated by byroot (Jean Boussier) over 3 years ago
          Updated by byroot (Jean Boussier) over 3 years ago
          
          
        
        
      
      (using Google Translate to understand the discussion, sorry if I misunderstood or missed things).
Since Object#pack1 might be deemed a bit too invasive, an alternative could be String.pack1(format, arg), or even String.pack(format, *args).
        
           Updated by jeremyevans0 (Jeremy Evans) about 2 years ago
          Updated by jeremyevans0 (Jeremy Evans) about 2 years ago
          
          
        
        
      
      I developed a patch for this that implemented the feature using Array.pack1 and was going to create a new feature request for it, but I'm glad to see there already is an existing feature request for it.  Here's my pull request for it: https://github.com/ruby/ruby/pull/8598
        
           Updated by Eregon (Benoit Daloze) about 2 years ago
          Updated by Eregon (Benoit Daloze) about 2 years ago
          
          
        
        
      
      Array.pack1(obj, format) -> String sounds weird since there is nothing about Array in there.
I think String.pack1(format, obj) is the best option.
(String#pack1(obj) is confusing because of existing Array#pack(format) which has the reverse order).
(IMO this is something a JIT should optimize but I understand that's hard on CRuby).
        
           Updated by matz (Yukihiro Matsumoto) about 2 years ago
          Updated by matz (Yukihiro Matsumoto) about 2 years ago
          
          
        
        
      
      Array.pack1 is unlikely because there is no connection between the responsibilities of the method and the Array class. I also disagree with String.pack1 for the same reason.
The most natural candidate is Object#pack1, but I question the need to pollute the namespace for this trivial method.
Matz.
        
           Updated by tenderlovemaking (Aaron Patterson) about 2 years ago
          Updated by tenderlovemaking (Aaron Patterson) about 2 years ago
          
          
        
        
      
      matz (Yukihiro Matsumoto) wrote in #note-7:
Array.pack1 is unlikely because there is no connection between the responsibilities of the method and the Array class. I also disagree with String.pack1 for the same reason.
The most natural candidate is Object#pack1, but I question the need to pollute the namespace for this trivial method.Matz.
Feature #18897 introduced a specialized instruction for Array#hash, but it created a new instruction called opt_newarray_send.  I think we could leverage that instruction for the case of an array literal + pack.  That would avoid the array creation.  I will try to make a patch.
        
           Updated by mame (Yusuke Endoh) about 2 years ago
          Updated by mame (Yusuke Endoh) about 2 years ago
          
          
        
        
      
      If we introduce a new method for this, I think it would be better to design a more descriptive API instead of reusing a hacky pack format directive, such as 0x1234.to_binary_string(4, endian: :big) #=> "\x00\x00\x12\x34".