Project

General

Profile

This project is closed and read-only.

Actions

Feature #3675

closed

String#prepend, String#>>

Feature #3675: String#prepend, String#>>

Added by sorah (Sorah Fukumori) about 16 years ago. Updated over 15 years ago.


Description

=begin
sorahです.

通常, Stringでの文字列を手前に破壊的に加えるのは, a = "foo" + a 等で行いますが,
直感で読みにくく, 記号などで書きにくくなっていると思います.

なので, String#prependと String#>> を追加するというのはどうでしょうか.

それぞれ以下のように機能します.

a = "bar"
a.prepend("foo") #=> "foobar"
p a #=> "foobar"

b = "bar"
"foo" >> b #=> "foobar"
p b #=> "foobar"

patchはこちらです (git diff --no-prefixにて生成):

diff --git string.c string.c
index 0aa2e6c..6c9be57 100644
--- string.c
+++ string.c
@@ -2055,6 +2055,43 @@ rb_str_concat(VALUE str1, VALUE str2)
}
}

+/*

    • call-seq:
    • str.prepend(other_str)  -> str
      
    • Prepend---Prepend the given string to str.
    • a = "world"
    • a.prepend("hello ") #=> "hello world"
    • a #=> "hello world"
  • */

+static VALUE
+rb_str_prepend(VALUE str, VALUE str2)
+{

  • StringValue(str2);
  • StringValue(str);
  • rb_str_update(str, 0L, 0L, str2);
  • return str;
    +}

+/*

    • call-seq:
    • str >> other_str -> other_str
      
    • Prepend---Prepend self string to other_str.
    • a = "world"
    • "hello " >> a #=> "hello world"
    • a #=> "hello world"
  • */

+static VALUE
+rb_str_prepend_to_another(VALUE str1, VALUE str2)
+{

  • return rb_str_prepend(str2, str1);
    +}

st_index_t
rb_memhash(const void *ptr, long len)
{
@@ -7524,6 +7561,8 @@ Init_String(void)
rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
rb_define_method(rb_cString, "concat", rb_str_concat, 1);
rb_define_method(rb_cString, "<<", rb_str_concat, 1);

  • rb_define_method(rb_cString, "prepend", rb_str_prepend, 1);
  • rb_define_method(rb_cString, ">>", rb_str_prepend_to_another, 1);
    rb_define_method(rb_cString, "crypt", rb_str_crypt, 1);
    rb_define_method(rb_cString, "intern", rb_str_intern, 0);
    rb_define_method(rb_cString, "to_sym", rb_str_intern, 0);
    diff --git test/ruby/test_string.rb test/ruby/test_string.rb
    index 02271ce..da2477f 100644
    --- test/ruby/test_string.rb
    +++ test/ruby/test_string.rb
    @@ -1882,4 +1882,36 @@ class TestString < Test::Unit::TestCase
    assert_equal('"\u3042\u3044\u3046"', "\u3042\u3044\u3046".encode(e).inspect)
    end
    end
  • def test_prepend_to_another
  • assert_equal(S("hello world"), "hello " >> "world")
  • foo = Object.new
  • def foo.to_str
  •  "b"
    
  • end
  • assert_equal(S("ab"), "a" >> foo)
  • a = S("world!")
  • b = S("hello ")
  • b >> a
  • assert_equal(S("hello world!"), a)
  • assert_equal(S("hello "), b)
  • end
  • def test_prepend
  • assert_equal(S("hello world!"), "world!".prepend("hello "))
  • foo = Object.new
  • def foo.to_str
  •  "b"
    
  • end
  • assert_equal(S("ba"), "a".prepend(foo))
  • a = S("world")
  • b = S("hello ")
  • a.prepend(b)
  • assert_equal(S("hello world"), a)
  • assert_equal(S("hello "), b)
  • end
    end
    =end

Updated by mrkn (Kenta Murata) about 16 years ago Actions #1

  • Category set to core
  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)

=begin

=end

Updated by matz (Yukihiro Matsumoto) about 16 years ago Actions #2

=begin
まつもと ゆきひろです

In message "Re: [ruby-dev:41969] [Feature #3675] String#prepend, String#>>"
on Tue, 10 Aug 2010 18:24:04 +0900, Sora Harakami writes:

|sorahです.
|
|通常, Stringでの文字列を手前に破壊的に加えるのは, a = "foo" + a 等で行いますが,
|直感で読みにくく, 記号などで書きにくくなっていると思います.

これは破壊的ではないですね。aに最初入っていた文字列は変更さ
れずに残ります。

|なので, String#prependと String#>> を追加するというのはどうでしょうか.

非常に興味深いです。ただ、いくつか気になる点があります。

(1) 実装上のことですが、appendと異なり、prependは、文字列領域
を拡張した上で、現在の文字列の内容をコピーし、それから引
数の内容を先頭からコピーすることになります。つまり、

  a = "foo" + a

 と比較して、コストはオブジェクトアロケーションひとつしか
 変わりません。それが本当にうれしいかやや疑問です。もっと
 も長い目で見るとGCへの負荷が軽いというメリットが出るケー
 スもあるでしょう。

(2) >> というのは考えてもみなかった面白い記法です。しかし、
現状の文字列のメソッドで、引数のほうに破壊的な変更を加え
るメソッドはなかったように思うので、やや躊躇します。もっ
とも、Stringクラスでなければ、引数に破壊的な変更を加える
メソッドはいくつもあるので、気にすることではないのかもし
れません。

他の方のご意見も聞きたいです。

                             まつもと ゆきひろ /:|)

=end

Updated by sorah (Sorah Fukumori) about 16 years ago Actions #3

=begin
sorahです.

2010/8/10 Yukihiro Matsumoto :

と比較して、コストはオブジェクトアロケーションひとつしか
変わりません。それが本当にうれしいかやや疑問です。もっと
も長い目で見るとGCへの負荷が軽いというメリットが出るケー
スもあるでしょう。
個人的にはa = "foo" + aより"foo" >> aや"foo".prependのほうが読みやすいと思うのですよね..

あとは少しベンチマークを行ってみましたが, String#prepend, String#>>は
いずれも a = "foo" + aより早いように見えました.

(2) >> というのは考えてもみなかった面白い記法です。しかし、
現状の文字列のメソッドで、引数のほうに破壊的な変更を加え
るメソッドはなかったように思うので、やや躊躇します。もっ
とも、Stringクラスでなければ、引数に破壊的な変更を加える
メソッドはいくつもあるので、気にすることではないのかもし
れません。
このパッチは何度かIRCのほうに出して議論していたのですが,
同じような事を言われました. 自分は他のクラスにあるのなら
別にいいのではないかと思いますが...

--
@sora_h - http://codnote.net/

=end

Updated by usa (Usaku NAKAMURA) about 16 years ago Actions #4

=begin
こんにちは、なかむら(う)です。

In message "[ruby-dev:41976] Re: [Feature #3675] String#prepend, String#>>"
on Aug.10,2010 22:23:13, wrote:

(2) >> というのは考えてもみなかった面白い記法です。しかし、
現状の文字列のメソッドで、引数のほうに破壊的な変更を加え
るメソッドはなかったように思うので、やや躊躇します。もっ
とも、Stringクラスでなければ、引数に破壊的な変更を加える
メソッドはいくつもあるので、気にすることではないのかもし
れません。

他の方のご意見も聞きたいです。

訓練されたRubyistは>>をメソッドとして見てしまうので「引数の方
に破壊的な変更を加える」と思ってしまうわけですが、字面だけ見
れば右項が変更されるのは割と素直な解釈なんじゃないかと思いま
す。
というわけで、悪くないんじゃないでしょうか。

それでは。

U.Nakamura

=end

Updated by mrkn (Kenta Murata) about 16 years ago Actions #5

=begin
むらたです。

On 2010/08/11, at 12:57, masayoshi takahashi wrote:

2010年8月11日10:20 U.Nakamura :

In message "[ruby-dev:41976] Re: [Feature #3675] String#prepend, String#>>"
on Aug.10,2010 22:23:13, wrote:

(2) >> というのは考えてもみなかった面白い記法です。しかし、
現状の文字列のメソッドで、引数のほうに破壊的な変更を加え
るメソッドはなかったように思うので、やや躊躇します。もっ
とも、Stringクラスでなければ、引数に破壊的な変更を加える
メソッドはいくつもあるので、気にすることではないのかもし
れません。

他の方のご意見も聞きたいです。

訓練されたRubyistは>>をメソッドとして見てしまうので「引数の方
に破壊的な変更を加える」と思ってしまうわけですが、字面だけ見
れば右項が変更されるのは割と素直な解釈なんじゃないかと思いま
す。
というわけで、悪くないんじゃないでしょうか。

訓練されているかどうかはさておき、素直な解釈としては、String#<<との
対比が気になります。
現状、

a = "aaa"
b = "bbb"
c = "ccc"
d = a << b << c
p [a,b,c,d] #=> ["aaabbbccc", "bbb", "ccc", "aaabbbccc"]

となるわけですが、

x = "xxx"
y = "yyy"
z = "zzz"
w = x >> y >> z
p [x,y,z,w]

は
["xxx", "xxxyyy", "xxxyyyzzz", "xxxyyyzzz"]
となるのでしょうか?
なんとなく、
["xxx", "yyy", "xxxyyyzzz", "xxxyyyzzz"]
となってほしいような気もするのですが、そうすると結合ルール的に
困った感じでしょうか。

でも、yが破壊されるのも形としては自然なんですかねえ。ちょっと
判断しづらいところです。

私は >> はシフト演算子で << と同じく左結合だから (x >> y) >> z の順で
評価されると式を見た瞬間に判断し、y も z も破壊される結果を期待しました。

私が Rubyist としてよりも C/C++ プログラマーとして訓練されている所為かもしれません。

--
Kenta Murata
OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062

本を書きました!!
『Ruby 逆引きレシピ』 http://www.amazon.co.jp/dp/4798119881/mrkn-22

E-mail:
twitter: http://twitter.com/mrkn/
blog: http://d.hatena.ne.jp/mrkn/

=end

Updated by usa (Usaku NAKAMURA) about 16 years ago Actions #6

=begin
こんにちは、なかむら(う)です。

In message "[ruby-dev:41994] Re: [Feature #3675] String#prepend, String#>>"
on Aug.11,2010 12:57:45, wrote:

x = "xxx"
y = "yyy"
z = "zzz"
w = x >> y >> z
p [x,y,z,w]

は
["xxx", "xxxyyy", "xxxyyyzzz", "xxxyyyzzz"]
となるのでしょうか?
なんとなく、
["xxx", "yyy", "xxxyyyzzz", "xxxyyyzzz"]
となってほしいような気もするのですが、そうすると結合ルール的に
困った感じでしょうか。

でも、yが破壊されるのも形としては自然なんですかねえ。ちょっと
判断しづらいところです。

その辺は私も気になりました。
が、結合則をいじるところまで踏み込むのはちょっと怖いですね。
やっぱり実使用例が出てこないと考察が進まないかなあ。

それでは。

U.Nakamura

=end

Updated by sorah (Sorah Fukumori) about 16 years ago Actions #7

=begin
sorahです。

結合法則をいじると別メソッドにも影響を及ぼしかねない (Integerの>>) ので、
このメソッドの実装を変えることになると思うのですが、
自分はどのように実装すべきなのかがわかりません。

--
Sora Harakami (iPad) - @sora_h
Blog: http://codnote.net
Detail: http://sorah.cosmio.net

On Aug 11, 2010, at 2:10 PM, "U.Nakamura" wrote:

こんにちは、なかむら(う)です。

In message "[ruby-dev:41994] Re: [Feature #3675] String#prepend, String#>>"
on Aug.11,2010 12:57:45, wrote:

x = "xxx"
y = "yyy"
z = "zzz"
w = x >> y >> z
p [x,y,z,w]

は
["xxx", "xxxyyy", "xxxyyyzzz", "xxxyyyzzz"]
となるのでしょうか?
なんとなく、
["xxx", "yyy", "xxxyyyzzz", "xxxyyyzzz"]
となってほしいような気もするのですが、そうすると結合ルール的に
困った感じでしょうか。

でも、yが破壊されるのも形としては自然なんですかねえ。ちょっと
判断しづらいところです。

その辺は私も気になりました。
が、結合則をいじるところまで踏み込むのはちょっと怖いですね。
やっぱり実使用例が出てこないと考察が進まないかなあ。

それでは。

U.Nakamura

=end

Updated by mrkn (Kenta Murata) about 16 years ago Actions #8

=begin
むらたです。

On 2010/08/10, at 22:23, Yukihiro Matsumoto wrote:

非常に興味深いです。ただ、いくつか気になる点があります。

(1) 実装上のことですが、appendと異なり、prependは、文字列領域
を拡張した上で、現在の文字列の内容をコピーし、それから引
数の内容を先頭からコピーすることになります。つまり、

a = "foo" + a

と比較して、コストはオブジェクトアロケーションひとつしか
変わりません。それが本当にうれしいかやや疑問です。もっと
も長い目で見るとGCへの負荷が軽いというメリットが出るケー
スもあるでしょう。

a >> b を内部的に

(i) a.length を維持したまま a << b する
(ii) b のポインタを a と共有し、
b.length = a.length + b.length と更新する。

こうすると a = "foo" + a と同程度の計算量で、
a >> b の記法を実現できると思いました。

--
Kenta Murata
OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062

本を書きました!!
『Ruby 逆引きレシピ』 http://www.amazon.co.jp/dp/4798119881/mrkn-22

E-mail:
twitter: http://twitter.com/mrkn/
blog: http://d.hatena.ne.jp/mrkn/

=end

Updated by nobu (Nobuyoshi Nakada) about 16 years ago Actions #9

=begin
なかだです。

At Thu, 12 Aug 2010 09:24:29 +0900,
Kenta Murata wrote in [ruby-dev:42008]:

a >> b を内部的に

(i) a.length を維持したまま a << b する
(ii) b のポインタを a と共有し、
b.length = a.length + b.length と更新する。

Copy-on-Write化を進めれば可能ですが、その代わりRSTRING_PTRが
null-terminateされていないケースが出てきます。現在でも
StringValueCStr()を呼ばない限りは保証はされないのですが、昔の前
提のまま依存している拡張ライブラリは修正が必要であり、どの程度影
響があるか予測できません。

--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦

=end

Updated by sorah (Sorah Fukumori) about 16 years ago Actions #10

=begin
普通に現在の実装ではだめなのですか.

2010/8/12 Kenta Murata :

むらたです。

On 2010/08/10, at 22:23, Yukihiro Matsumoto wrote:

非常に興味深いです。ただ、いくつか気になる点があります。

(1) 実装上のことですが、appendと異なり、prependは、文字列領域
を拡張した上で、現在の文字列の内容をコピーし、それから引
数の内容を先頭からコピーすることになります。つまり、

a = "foo" + a

と比較して、コストはオブジェクトアロケーションひとつしか
変わりません。それが本当にうれしいかやや疑問です。もっと
も長い目で見るとGCへの負荷が軽いというメリットが出るケー
スもあるでしょう。

a >> b を内部的に

(i) a.length を維持したまま a << b する
(ii) b のポインタを a と共有し、
b.length = a.length + b.length と更新する。

こうすると a = "foo" + a と同程度の計算量で、
a >> b の記法を実現できると思いました。

--
Kenta Murata
OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062

本を書きました!!
『Ruby 逆引きレシピ』 http://www.amazon.co.jp/dp/4798119881/mrkn-22

E-mail:
twitter: http://twitter.com/mrkn/
blog: http://d.hatena.ne.jp/mrkn/

--
@sora_h - http://codnote.net/

=end

Updated by mrkn (Kenta Murata) about 16 years ago Actions #11

=begin
むらたです。

On 2010/08/18, at 8:32, Sora Harakami wrote:

普通に現在の実装ではだめなのですか.

現在の実装を否定するものではありません。

On 2010/08/10, at 22:23, Yukihiro Matsumoto wrote:

非常に興味深いです。ただ、いくつか気になる点があります。

(1) 実装上のことですが、appendと異なり、prependは、文字列領域
を拡張した上で、現在の文字列の内容をコピーし、それから引
数の内容を先頭からコピーすることになります。

この見解に対する反論の一つとして提示しているだけです。

中田さんが [ruby-dev:42010] で

On 2010/08/12, at 12:46, Nobuyoshi Nakada wrote:

Copy-on-Write化を進めれば可能ですが、その代わりRSTRING_PTRが
null-terminateされていないケースが出てきます。現在でも
StringValueCStr()を呼ばない限りは保証はされないのですが、昔の前
提のまま依存している拡張ライブラリは修正が必要であり、どの程度影
響があるか予測できません。

と仰っているように、文字列を共有させると Ruby の処理系自身や
拡張ライブラリに大きな影響を与える可能性があって、
実現するにしても慎重にならざるを得ません。

--
Kenta Murata
OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062

本を書きました!!
『Ruby 逆引きレシピ』 http://www.amazon.co.jp/dp/4798119881/mrkn-22

E-mail:
twitter: http://twitter.com/mrkn/
blog: http://d.hatena.ne.jp/mrkn/

=end

Updated by matz (Yukihiro Matsumoto) about 16 years ago Actions #12

=begin
まつもと ゆきひろです

In message "Re: [ruby-dev:42061] Re: [Feature #3675] String#prepend, String#>>"
on Wed, 18 Aug 2010 13:31:13 +0900, "Akinori MUSHA" writes:

|String#>> だと、レシーバが文字列かそのサブクラスのインスタンス
|限定になるので #to_str を持った文字列もどきはダメということに
|なりますね。x.to_str + s も切なくて "#{x}s" としたりもするので、
|s が殿様な感じがする x.to_str >> s は嫌かも(笑)。

APIデザイナの希望としては to_str を持つオブジェクトは、
ポリモルフィズム的にStringの他のメソッドも持っていてほしいの
で、「to_strはあるが >> はない」ということは起きないようにオ
ブジェクトを設計してほしいと思っています。

=end

Updated by shyouhei (Shyouhei Urabe) about 16 years ago Actions #13

  • Status changed from Assigned to Closed

=begin
String#prepend has been accepted as revision r29120.

Other proposals including String#>> are pending.
=end

Actions

Also available in: PDF Atom