Search | Synergex.com | Contact Us | Resource Center Login | Home|
News

What is the output of the following program?

namespace spaghetti

    public class noodle
      public property hasTomato, @sauce
      method get
      proc
        mreturn new sauce("marinara")
      end
      endproperty

      public static method op_Explicit, @sauce
      in req pasta, @noodle
      proc
        mreturn new sauce("alfredo")
      end
    endclass

    public class sauce
      public method sauce
      in req flavor, a
      proc
        m_flavor = flavor
      end

      public property hasTomato, string
      method get
      proc
          if (m_flavor == "marinara")
            mreturn "yes!"
          mreturn "sorry, no"
      end
      endproperty

      public static method op_Explicit, a
      in req covering, @sauce
      proc
        mreturn covering.hasTomato
      end

      private m_flavor, string
    endclass

endnamespace

main
record
    vermicelli,          @noodle

proc
    open(1,o,"TT:")
    vermicelli = new noodle()
    writes(1, (a)(sauce)vermicelli.hasTomato)
end

a. “yes!”
b. “sorry, no”
c. An invalid cast error at compile time
d. An invalid cast error at run time

Explanation
In the WRITES statement, we’re casting to (a) to output the result. What follows is cast as (sauce). Since the sauce class provides a static method op_Explicit whose return type is a, this will work. The noodle class can be cast as a (sauce), thanks to its op_Explicit method, and can also return a sauce from its hasTomato property. So, no  casting error will occur. But which method gets invoked?  If the cast occurs first, then the hasTomato method would apply to the sauce returned by the noodle.op_Explicit (“alfredo”), which would return “sorry, no”. If the property evaluates first, then you’d get the sauce returned from hasTomato (“marinara”), whose op_Explicit would return “yes!”

Without explicit parentheses, member references have priority over a cast. That is, the cast is applied to the result of the full invocation. Thus, hasTomato returns a sauce of the “marinara” flavor, which gets superfluously cast as (sauce), and then re-cast as (a) to produce “yes!”  If you had wanted the other result, you would express the reference as “(a)((sauce)vermicelli).hasTomato”

We didn’t randomly choose a spaghetti theme for this example. It demonstrates some of the confusion that developers can create by using bad design principles. The property name hasTomato, for instance, serves completely different functions in the noodle and sauce classes, and even returns different types.  The use of op_Explicit for casting, while often useful, was not only gratuitous here but also added to the confusion of precedence. Sticking to the usual member reference syntax would have made that clear.  For instance, assuming the addition of a few methods, vermicelli.hasTomato.ToString() is an explicitly different series of calls than vermicelli.ToSauce().hasTomato.ToString().


More information about News and Events

Contact Synergex to learn more about  News and Events
Talk to Us: Synergy/DE instant call-back

Looking to extend the power of your Synergy/DE-based applications? Click the Synergy/DE instant call-back button to talk to us.