Extension method for String not working

Hello
i tried to define an string append extension method, but there is nothing appended. What i’m doing wrong here ?

namespace Test;
interface
type
Program = assembly static class
public
class method Main(args:array of String);
end;

extension method String.Append(s:String);
begin
self:=self+s;
end;

implementation

class method Program.Main(args:array of string);
var s:String;
begin
s:=‘1’;
s.Append(‘2’);
writeLn(s);
end;

end.

Two things at play here:

(a) Strings are immutable
(b) assigning to “self” in an extension method will not change the variable that the extension method was called on.

s:=‘1’;  
s.Append(‘2’);

s is reference to a string objects that has a value of “1”, and that string objects will never ever change its value. And the only way to change the value of “s” itself, is to point it to a different string - which this code does not do.

extension method String.Append(s:String);
begin
  self:=self+s;
end;

this creates a new string object that combines the two strings, and then essentially… does noting with it.

Once could argue that the compiler shoukld not allow assignment to self; that is probably a side effect of how extension methods work, under the hood. I’ll bring that up for discussion with the compile team…

The extension method does exactly what it should, adding the strings to a new combined one and assigning this to ‘self’ (as can be seen by debugger).
The only ‘missing’ thing is the return of this new value.
Background is that i was rewriting some code and tried to replace StringBuilder with String. So i tried to replace the nice little ‘Append’ function with an extension method. (For me it looks somehow clearer compared to the Plus assignment).
But i see that the C# compiler is doing it the same way :frowning:

No, exactly how marc said, you create a new object, but the debugger shows the new object. There is no way you can modify a string, it’s readonly. You cannot replay StringBuilderby string. The main reason for StringBuilder is to support this kind of issues.

Changing this would possibly break existing code. It’s absolutely legal to change self in the method and use it locally, but it will just not go anywhere.
It might be a good idea to emit a warning that the new instance will be lost at the end of the method, but not allow it is probably not the best idea. Just my opinion.

Your method doesn’t return a value though. How do you propose that s gets changed to a different class instance, merely by calling a method on it?

Yes, StringBuilder, or some otherwise mutable type (eg a wrapper around String) would be the only option for this. the String class is provided by the .NET runtime, and its immutable, and there’s nothing we or you could do about it (if we wanted to ;). Same goes for String on Cocoa and Java, and on Island we have modeled String to match.

It’s also worth mentioning that from an API design perspective, if your Append were to work as two expect, it would work orthogonally to all other existing “modification” methods on string, such as Replace, etc, since

s.Replace("a"', "b");

will also not so what you’d “expect”, when in this mindset. Replace doesn’t change s either; it returns a new value (which you’d ignore). If you want to define an Append that works in symmetry with the rest of String, define it as

extension method String.Append(s:String): String;
begin
  result := self+s;
end;

and call it as

s := "1";  
s := s.Append("2");

This would work, and be more consistent. Also note that there’s already s.Concat(), which does exactly this ;).

Yeah, I was wondering about that. I’m not sure I see a valid/reasonable/sane scenario where one would/should do this (argument for not allowing it), but of course that doesn’t mean someone hasn’t done so in existing code :joy:.

I’m still undecided on where to go with this.

Well, “legal” is, for Oxygene, what we say it is :).

I’m wondering of someone can come up with an argument for doing this (aside from “I did, and got away with it”). What can be gained by changing self, rather than using local var, that would be worth the confusion it causes?

:+1::joy:

I agree, but people do things no one else can understand :wink:

Yeah, but that’s an argument for considering it broken, and disallowing it, even if thats a “breaking change”. (every bug fix is a breaking change, on some level ;).

Luckily we’re not Swift, where “the compiler implementation is the spec”.

1 Like

Thank you. It seems my expectation was wrong. Sorry.

Btw, while experimenting a little bit with assigning self/this within a class method i encountered that the C# compiler emits an error
CS1604: Cannot assign to ‘’ because it is read-only,
while the Oxygene compiler doesn’t.
Maybe it would be a good idea to introduce this error to Oxygene
(and also within extension methods ?)

Best Regards

1 Like

“this” was removed in my post…

Yes, that’s what me and Fredy discussed above. Ive decked to gofer disallowing it, as I agree its confusing and misleading to allow this. (if any issues corpus, we can revisit); todays build shuld have that fix.