Q: Should String.upcase! work on a segment of a string?

M

Mike Hall

Question: Should String.upcase! work on a segment of a string?

We can assign to a sub-string, so I thought that a bang-method might also work on a sub-string.

s = 'AA11zz' # define a string
s[4..5].upcase! # try to change part of it
=> "ZZ" # yeah, ok, the new string is changed, but...
=> "AA11zz" # the original string wasn't affected
s[4..5] = s[4..5].upcase # so, do it by-hand
=> "ZZ"
s # and it's ok
=> "AA11ZZ"

Are there edge cases where this wouldn't be appropriate?
 
G

Gavin Sinclair

Mike said:
Question: Should String.upcase! work on a segment of a string?

We can assign to a sub-string, so I thought that a bang-method might
also work on a sub-string.

s = 'AA11zz' # define a string
s[4..5].upcase! # try to change part of it
=> "ZZ" # yeah, ok, the new string is changed,
but...
=> "AA11zz" # the original string wasn't affected

s is one object; s[4..5] is another. What you do to the second object is
none of the first's business.
s[4..5] = s[4..5].upcase # so, do it by-hand
=> "ZZ"
s # and it's ok
=> "AA11ZZ"

That's because of (psuedo-code)

class String
def []=(index, value)
case index
when Range then ...
when Numeric then ...
...
end
end
end
Are there edge cases where this wouldn't be appropriate?

There's no way to make s[4..5].upcase! do what you suggest.

Cheers,
Gavin
 
N

nobu.nokada

Hi,

At Thu, 9 Sep 2004 09:35:04 +0900,
Mike Hall wrote in [ruby-talk:111938]:
We can assign to a sub-string, so I thought that a bang-method might also work on a sub-string.

It isn't suitable for Ruby's object model, as mentioned
already.

An idea instead, what's about optional arguments which give the
range?
 
M

Mark Hubbart

Question: Should String.upcase! work on a segment of a string?

We can assign to a sub-string, so I thought that a bang-method might
also work on a sub-string.

s = 'AA11zz' # define a string
s[4..5].upcase! # try to change part of it
=> "ZZ" # yeah, ok, the new string is changed,
but...
=> "AA11zz" # the original string wasn't affected
s[4..5] = s[4..5].upcase # so, do it by-hand
=> "ZZ"
s # and it's ok
=> "AA11ZZ"

Are there edge cases where this wouldn't be appropriate?

A string and it's substrings (as accessed by [] and slice) are not
related. When you create a substring by taking a slice, it returns a
copy of that section of data.

Still, this was one of the conveniences I missed from PHP. Here's an
idea I've played around with a few times (dirty hack follows):

class SubString
def initialize(string, range)
@string, @range = string, range
end
def upcase!
@string[@range] = @string[@range].upcase
end
# [...]
end

class String
def sub_str(range)
SubString.new(self, range)
end
end

foo.sub_str(2..4).upcase!
==>"STI"
foo
==>"teSTIng foo testing"

foo.sub_str(/foo/).upcase!
==>"FOO"
foo
==>"teSTIng FOO testing"

cheers,
Mark
 
M

Mike Hall

Gavin Sinclair wrote:

We can assign to a sub-string, so I thought that a bang-method might
also work on a sub-string.
s = 'AA11zz' # define a string
s[4..5].upcase! # try to change part of it
=> "ZZ" # yeah, ok, the new string is changed,
but...
=> "AA11zz" # the original string wasn't affected

s is one object; s[4..5] is another. What you do to the second object is
none of the first's business.

I don't understand that... we can outright assign to the substring and it _does_ affect the original string.

I agree that pulling out s[4..5] (using it on the RHS) will give me a new object, that's cool.

But -- if the string range reference is on the LHS, then it refers to a segment of 's', not some new object. That's what I'm after. If s.upcase! affects s, then it would be cool if s[4..5].upcase! also affected (a portion) of s.

But it doesn't, and I guess it won't.
OK. Thanks, everyone!
 
A

Austin Ziegler

Gavin said:
We can assign to a sub-string, so I thought that a bang-method might
also work on a sub-string.
s = 'AA11zz' # define a string

s[4..5].upcase! # try to change part of it
=> "ZZ" # yeah, ok, the new string is changed,
but...
s
=> "AA11zz" # the original string wasn't affected

s is one object; s[4..5] is another. What you do to the second object is
none of the first's business.

I don't understand that... we can outright assign to the substring and it _does_ affect the
original string.

I agree that pulling out s[4..5] (using it on the RHS) will give me a new object, that's cool.

There's your conceptual error: there is no distinction of RHS and LHS.
There's a method, String#[]=, that is being used on the LHS when you
do:

s[4..5] = s[4..5].upcase

So that's actually:

s.__send__:)"[]="), 4..5, s[4..5].upcase)

String#[] returns a new object; String#[]= performs an indexed
assignment that is interpreted in String as replacing 4..5 with the
value provided.

-austin
 
M

Markus

Gavin Sinclair wrote:

We can assign to a sub-string, so I thought that a bang-method might
also work on a sub-string.
s = 'AA11zz' # define a string

s[4..5].upcase! # try to change part of it
=> "ZZ" # yeah, ok, the new string is changed,
but...
s
=> "AA11zz" # the original string wasn't affected

s is one object; s[4..5] is another. What you do to the second object is
none of the first's business.

I don't understand that... we can outright assign to the substring and it _does_ affect the original string.

I agree that pulling out s[4..5] (using it on the RHS) will give me a new object, that's cool.

But -- if the string range reference is on the LHS, then it refers to a segment of 's', not some new object. That's what I'm after. If s.upcase! affects s, then it would be cool if s[4..5].upcase! also affected (a portion) of s.

But it doesn't, and I guess it won't.
OK. Thanks, everyone!

DON'T TRY THIS TRICK AT HOME

It is possible to do what you are asking, but I seriously doubt it is
worth the trouble. A sketch (NOT a complete or robust implementation):

class String
alias at []
def [](arg)
case arg
when Range then A_magic_substring.new(self,arg)
else at(arg)
end
end
end

class A_magic_substring
attr_reader :host,:loc
def initialize(h,l)
@host = h
@loc = l
end
def upcase!
@host[@loc] = @host.at(@loc).upcase
end
def to_str
@host.at(@loc)
end
def to_s
to_str
end
def inspect
to_str
end
end

s = "My string"
p s
p s[3..5]
s[3..5].upcase!
p s
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top