Coffeehouse Thread

48 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

C++ needs extension methods

Back to Forum: Coffeehouse
  • User profile image
    evildictait​or

    , BitFlipper wrote

    BTW this also allows you to create static methods.

    Static extension methods don't make sense, because extension methods are syntactic sugar around being able to use the "." notation on an object. Static methods don't use that "." so there's no point.

    class StringHelpers { 

    static int StringToIntDoesntNeedToBeAnExtensionMethod(string str)
    {
      return int.Parse(str);
    }

    int ButItDoesIfItRequiresDotSyntax(this string str)
    {
      return int.Parse(str);

    void Main()
    {

      int i = StringToIntDoesntNeedToBeAnExtensionMethod("foo");

      int j = "foo".ButItDoesIfItRequiresDotSyntax();

  • User profile image
    Sven Groot

    , evildictaitor wrote

    *snip*

    That's not C++.

    They still extend C++, though. There are various MS-specific #pragmas, some behaviours that deviate from the standard, various __ keywords like __declspec (those may be allowed by the standard, but using them still breaks portability), the COM smart pointer #import directive, and I'm sure there's more I'm forgetting right now.

  • User profile image
    Bass

    @evildictaitor:

    We must go deep into the philosophy of what it means to be a type. Methods can naturally belong to classes, while fields belong to objects.

  • User profile image
    evildictait​or

    , Sven Groot wrote

    They still extend C++, though.

    That's true (tbh I'm not sure a standards compliant C++ exists at all). But that doesn't mean making it less standards compliant would make it better.

  • User profile image
    Bass

    Standards compliant means it implements the standard. Mac OS X is POSIX compliant even though it has an entire universe of APIs besides POSIX. No POSIX-compliant OS just implements POSIX. Web standards are much the same. Good browser developers try not to pollute the namespace with browser-specific extensions though (ie: prefix with moz or webkit).

    The point of standards is that there is a common baseline that just works. If I write standard compliant code I expert it to work on all standard compliant platforms (if that be compilers, OSes, browsers, etc.). This is very helpful for portability, having the baseline with clearly defined boundaries. But it does not mean every platform has to be bit-for-bit the same interface.

  • User profile image
    evildictait​or

    , Bass wrote

    Standards compliant means it implements the standard.

    No, it means that it complies the standard. The C++ standard includes as normative the C++ grammar and parsing rules, so anyone who extends that is not standards compliant.

    Mac OS X is POSIX compliant even though it has an entire universe of APIs besides POSIX.

    So is Windows Smiley

    Web standards are much the same.

    Web standards don't exist. Nobody owns the web. On the other hand, C++ is an ISO standard.

    The point of standards is that there is a common baseline that just works. 

    The point of standards is to be standard. If I write some code on my standards compliant machine it should succeed or fail in the same way on your standards complaint machine.

  • User profile image
    cbae

    @BitFlipper: In your example, where is the field "wordCount" declared? And how is it declared? Is it a static field? If it is, then it's useless since all instances would share the same value. If it's not static, how can this static extension class reference it?

  • User profile image
    Bass

    @evildictaitor:

    I think it's fine as long as there is a way to enforce strict standards compliance (eg: a compiler switch). Just my opinion.

    In school for C code we used to pass the -ansi flag to gcc to ensure strict[er] standards compliance. I've never seen that done in the "real world" yet, since project design often guaranteed to use a specific compiler and platform anyway.

    Apparently you can get finer grained than that with the -std flag. gcc also documents all it's extensions, which is nice (and educational, I think).

    It's interesting that the Linux kernel actually uses many of these extensions, so gcc is typically the only compiler that can reliably compile Linux. Although Clang has been implemented many of gcc's extensions and has made a lot of progress in this.

    So anyway I think the point is, extensions to standard languages are pretty common and not very controversial.

  • User profile image
    BitFlipper

    @evildictaitor:

    It makes sense when you want to do something like:

    public static extension class string
    {
        public static string Longest(string s1, string s2)
        {
            if (s1 == null)
                return s2;

            if (s2 == null)
                return s1;

            return s1.Length >= s2.Length ? s1 : s2;
        }
    }

    ...or...

    public static extension struct float
    {
        public static float[] FromPcm16(Int16[] srcBuffer)
        {
            var dstBuffer = new float[srcBuffer.Length];

            // Convert to float...
           
            return dstBuffer;
        }
    }

    , cbae wrote

    @BitFlipper: In your example, where is the field "wordCount" declared? And how is it declared? Is it a static field? If it is, then it's useless since all instances would share the same value. If it's not static, how can this static extension class reference it?

    You misunderstood the example."wordCount" is not a field, it is a local variable inside the method (or property) that is used to calculate the number of words. That is why I specifically said you will get a compiler error if you try to add field members. I'll edit the example to make it more clear.

  • User profile image
    Blue Ink

    In principle, I agree that language extensions aren't evil as long as the compiler (or browser) adheres to the standard. In practice, it's a bad idea.

    Assuming that you design an useful feature, based on an actual need, there are several possible disasters that might happen:

    - the relevant standard body decides to implement that feature, but with a different syntax. Politics aside, that's quite likely to happen as nobody is perfect and they have the 20/20 hindsight your implementation provides. You end up with a compiler that implements the same feature in two different ways, one of which (yours) is considered inferior. Ouch.

    - the standard body decides to implement that feature, but with different semantics. You have to decide whether it's better to break everybody's code and documentation or fail to implement the standard correctly.

    - Worst of all: the standard body decides to implement an unrelated, but more visible feature whose syntax clashes with yours. Good luck fixing that.

    If the browser wars taught us anything is that the only way to properly extend a standard is to participate and put pressure on the committees. With a big smile, of course.

  • User profile image
    exoteric

    , Bass wrote

    @evildictaitor:

    I think it's fine as long as there is a way to enforce strict standards compliance (eg: a compiler switch). Just my opinion.

    In school for C code we used to pass the -ansi flag to gcc to ensure strict[er] standards compliance. I've never seen that done in the "real world" yet, since project design often guaranteed to use a specific compiler and platform anyway.

    Apparently you can get finer grained than that with the -std flag. gcc also documents all it's extensions, which is nice (and educational, I think).

    It's interesting that the Linux kernel actually uses many of these extensions, so gcc is typically the only compiler that can reliably compile Linux. Although Clang has been implemented many of gcc's extensions and has made a lot of progress in this.

    So anyway I think the point is, extensions to standard languages are pretty common and not very controversial.

    I think you have a good point here.

    I also like the way you can switch on extensions for GHC.

    There was also quite some negative reactions to some new WinRT extensions for C++ in one or more video posts on this site - but why, if it's restricted to a switchable compiler extension (which admittedly, I'm assuming it is).

    As for extension methods, I seem to remember D having something close to it, where you can declare a function on a type, including a primitive type and instead of calling it like foo(x) you can say x.foo. But that's more like an extension property.

    Anyway, there are good uses and probably not so good uses for extension methods but look at LINQ and how useful they are there. Also, don't extension methods prevent you from using implementation details (no access to private and protected parts)? This makes them just syntactic sugar for static functions and how can one argue against those?

  • User profile image
    Sven Groot

    @Blue Ink: The way to avoid the second and third problem is to stick to keywords that the standard reserves for extensions (in C++, this is any keyword or identifier starting with __ or _ and a capital; in CSS the equivelent is the -ms and -moz prefixes I guess).

    The disadvantage there is that it can lead to horribly ugly syntax (witness the first version of Managed C++).

  • User profile image
    evildictait​or

    , BitFlipper wrote

    public static extension class string

    {
        public static string Longest(string s1, string s2)
        {
            if (s1 == null)
                return s2;

            if (s2 == null)
                return s1;

            return s1.Length >= s2.Length ? s1 : s2;
        }
    }

    ...or...

    public static extension struct float
    {
        public static float[] FromPcm16(Int16[] srcBuffer)
        {
            var dstBuffer = new float[srcBuffer.Length];

            // Convert to float...
           
            return dstBuffer;
        }
    }

    What's wrong with 

    public static class StringHelper

    {
        public static string Longest(string s1, string s2)
        {
            if (s1 == null)
                return s2;

            if (s2 == null)
                return s1;

            return s1.Length >= s2.Length ? s1 : s2;
        }
    }

    ...or...

    public static struct FloatHelper
    {
        public static float[] FromPcm16(Int16[] srcBuffer)
        {
            var dstBuffer = new float[srcBuffer.Length];

            // Convert to float...
           
            return dstBuffer;
        }
    }

  • User profile image
    BitFlipper

    @evildictaitor:

    Then why have extension methods at all when helper classes is all we need?

  • User profile image
    Sven Groot

    , BitFlipper wrote

    @evildictaitor:

    Then why have extension methods at all when helper classes is all we need?

    The difference is that invoking a method as if it was an instance method if it logically operates on that instance has actual readability benefits (especially in the context of LINQ, which the feature was invented for), e.g. list.Where(condition) vs. Enumerable.Where(list, condition), whereas the difference between writing String.Longest or StringHelper.Longest isn't that great.

  • User profile image
    BitFlipper

    Well static methods wasn't my main point, I just threw it in to show that such features can be readily added using the suggested syntax, while the current syntax makes such features difficult. What would extension properties look like using the existing syntax? Nobody knows because it just doesn't work with what we have now. The syntax I am suggesting does not have this problem because it is pretty obvious what properties would look like.

  • User profile image
    Sven Groot

    @BitFlipper: Oh yeah, I definitely agree that there could've been better syntax for declaring them (like the "extension class" idea).

  • User profile image
    SteveRichter

    , BitFlipper wrote

    I still think the way extensions in C# was implemented is wrong. It looks and feels like they could not really come up with an ideal syntax and ended up with the awkward result we have today. My suggestion is to do it this way:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public static extension class string
    {
        /// <summary>
        /// Shows how a method is implemented
        /// </summary>
        public int GetWordCount()
        {
             var wordCount = 0;
             // Code that counts words
             return wordCount;
        }
     
        
    }

     

    keep in mind that extension methods apply to all types, like enums and interfaces.

    Also, I like that an extension method can be called on a this value that is null.

    For a lot of the classes I create I code two extension methods. One, named "ToXElement" returns the object in XElement form. The 2nd, named "[ClassName]OrDefault" is an extension of XElement and returns the object instance from an XElement.  Being able to test for null in an extension method is great when going from XElement to object because you never know if the XDocument contains your XElement or not. And these two methods belong in the same source file with the class they are extending, despite one apply to XElement and the other to the actual class.

     

      public static class PresentationSpaceExt  {    public static XElement ToXElement(this PresentationSpace Space, XName Name)    {      if (Space == null)        return new XElement(Name, null);      else      {        XElement xe = new XElement(Name,             new XElement("Fields",               from c in Space.Fields               select c.ToXElement("Field")),               Space.Dim.ToXElement("Dim"),               Space.CursorLocation.ToXElement("CursorLocation")          );        return xe;      }    }    public static PresentationSpace PresentationSpaceOrDefault(      this XElement Elem, XNamespace ns, PresentationSpace Default = null)    {      if (Elem == null)        return Default;      else      {        var dim = Elem.Element("Dim").PresentationSpaceDimOrDefault(ns, null);        var loc = Elem.Element("CursorLocation").DisplayLocationOrDefault(ns, null);        var flds =        from sam in Elem.Element(ns + "Fields")          .Elements(ns + "Field")          select sam.PresentationSpaceFieldOrDefault(ns, null) ;        var ps = new PresentationSpace(loc, dim, flds);        return ps;      }    }  }

     

     

     

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.