Generalized class-helpers/pseudo-objects?

I’ve been toying with the idea of generalized “pseudo-object syntax”, which would essentially be a form of syntax sugar.
It would allow passing the first parameter of a function call with the method syntax, f.i.

i.IntToStr();
i.Inc( 2 );

would be understood as being just a syntaxical variation of

IntToStr( i );
Inc(i, 2);

Essentially, every class-less  function/procedure could become a generalized class helper, that could operate on just about any type. Additionnally (or declaratively) you could also use a variation of the declaration f.i.

function Integer.IntToString() : String

could be equivalent to

function IntToString( Self : Integer ) : String

Of course there are some visibility issues to decided on, f.i. if I have a myClass.ToString method, would it take precedence over a ToString(myClass) function (I would say it should)? and whether such an extensibility would be implicit or declarative?
Do you know any language that implements such an approach?

13 thoughts on “Generalized class-helpers/pseudo-objects?

  1. >Do you know any language that implements such an approach?

    Sounds abit like Ruby, where all primitives (i.e Integer, String) are actually objects.

    This allows you to “monkey patch” these classes to add additional functionality. For example, I can add a method to the Integer class called commify, which enables me to then write 12321.commify, which produces “12,321”

  2. That looks like extension methods in C#.

    I can write:

    public static class Foo
    {
    public static string IntToStr(this int i) { return i.ToString(); }
    }

    And call it with either:

    s = Foo.IntToStr(1);

    …or:

    s = 1.IntToStr();

    The “this” in front of the argument enables this special syntax, which is done at compile time — the code generated for both forms is identical. The method is required to be static (a class method, in Delphi terms), and is required to be a member of a static class. The reasons why will be obvious, I think.

  3. I should add: A huge win from extension methods is that you can add new features to an interface without requiring interface implementers to support them.

    If I have an IBits with an XOR, I can then create extension methods for AND and OR and NOT which “look” like IBits.AND, etc., even though an implementer of IBits need only implement XOR.

  4. @Craig Stuntz

    “The reasons why” ?

    Is there a reason beyond the fact that C# simply doesn’t support first class functions and procedures ? A function HAS to be a member of some class because a function cannot exist without that redundant syntactic scaffolding.

  5. @Jolyon Smith Instance methods take precedence over extension methods when both are in scope. So if you had a TMyClass.Foo and an extension method Foo accepting a first argument of TMyClass, then the instance method would be called on a reference of type TMyClass.

    But in the example I gave IBits has no AND. Since C# (like Delphi) is structurally (instead of nominally) typed, the extension method would be called, because the reference is of type IBits, and MyBits (which implements IBits) having a method named AND doesn’t change what you can do with a reference of type IBits. Only by adding an AND member to IBits (a breaking change, forcing implementers to alter their code) would you supercede the extension method for a reference of type IBits.

    Regarding “the reasons why,” sure, class-less functions would work, too, if C# had them. They would be fine for a “Delphi version” of this feature.

    But I was distinguishing between static (class) methods and instance methods, and that distinction is the same for C# vs. Delphi.

  6. Bah! I reversed structural and nominative type systems in editing the comment above. Delphi and C# are both nominally typed, not structurally typed. The rest of the comment should make more sense with that fix!

  7. it’s a pretty neet idea, however this should allow me to do something like:
    var x: integer;
    begin
    x := 20;
    x.inttostr().strtoint().inttostr().strtoint()
    end;
    as many times as I want, correct? otherwise it’s not really useful…
    P.S. Eric you’re doing a very good job with DWScript, keep it up, it might get the most hardcore scripting language out there — not to mention that the cross platform compiler is right around the corner, it will get DWScript to new heights!!

  8. I have been thinking about stuff like this for a long time only i wanted it for Delphi and FreePascal, apparently i’m not the only one. It resembles the Prototype concept in JavaScript as in String.Prototype.Format .
    I don’t know why it was never supported by default in Delphi/FPC, it looks simple enough and is already done for classes (“Self” hidden parameter) just that you don’t declare an explicit “helper/extender” and not being declared as if the type was an interface/class will make many non-delphi programmers happy because they don’t know what CTRL+C does and always complain about declaring stuff twice 🙂
    Pseudo-objects would be very appreciated as syntactic sugar, also Google’s Go might have some other syntactic sugar we might like to use in the future for Pascal compilers.

  9. You’re slowly adding to DWScript the syntactic sugar I always hoped Borlancadero would add to Delphi. I’ve always wanted to do something like 2.days.ago in Delphi 😉

    Thanks, and keep the good work!

Comments are closed.