Improving semantics through function properties

Any function that accepts only one parameter can be called as if it were a property, and this applies to built-in system functions, your own custom functions, and even .NET methods alike. Instead of doing it like Report50001.SetDefaultPostingDate(101015D) you can always do it like Report50001.SetDefaultPostingDate := 101015D. Of course you can improve semantics of your code significantly if you simply call the function PostingDate instead of SetDefaultPostingDate, then you can just write Report50001.PostingDate := 101015D;

Remember – this works for all function types, even .NET method calls.

14 thoughts on “Improving semantics through function properties”

  1. Neat trick. It seems only to work in newer versions. I tested 2009R2 and it does not work, in NAV2015 it works.

    Since it is not common knowlegde, using this might result in people spending time figuring out what this is.

    1. I found it out accidentally a couple of weeks ago, while doing some work on a NAV 5.0 database for a customer – I find it strange it doesn’t work in 2009R2, since it certainly works on 5.0, 2013R2 and 2015.

  2. Just re-tested. I cannot get it to work in my customers 2009 R2 database.

    This was the first C# version, maybe Microsoft first killed it and later re-enabled it becuase of partner feedback?

    Maybe its me. 😉

    1. Then try a report in NAV 2009 R2 –> Sections –> OnPreSection:
      CurrReport.SHOWOUTPUT := FALSE instead of
      CurrReport.SHOWOUTPUT(FALSE);

      I prefer the first version for quite a long time 🙂

      1. Yes, I also know about the built-in function/properties, their usage is documented and obvious from the Symbol menu syntax description. However, I only recently found out that it works also on your custom functions, and only today that it also works on .NET methods.

  3. Hey Vjeko, are you suggesting that one parameter functions should be called through assignment? I.e.,

    Function.Paramater := Value;

    If so, I would wholeheartedly disagree – this makes semantics more confusing.
    My thoughts when seing code like that would be – Is this a Table.Field expression? Object.Properrty? OR something else?. I would even encourage to refrain from calling parameterless functions without parenthesis, as it leads to similar confusion.

    I.e., I’ll always encourage to do this:

    Object.Function();

    where the function does not take any parameters. Parenthesis here are what theory calls “syntactic sugar” – they make the code more readable, because you instantly know this is a function, not a property or field.

  4. Vytenis – I am not suggesting that one parameter functions should be called through assignment. What I am saying here is that it is possible. Also, what I am saying is that if you have certain “property assignment” functions, which sole purpose is to allow other objects set the value of internal variables (functions that receive NewSomething and then do Something := NewSomething), you can improve semantics by calling them as property assignment instead.

    For example, there are tons of situations where you call some Report.RUN, and just before that you call some SetDefaults(0D,Cust.”No.”,0) or whatever. This SetDefaults is very unreadable, and semantically confusing.

    My suggestion here is to replace that with functions called PostingDate, CustomerNo, NoOfIterations, and then call them like this:

    MyReport.PostingDate := 0D;
    MyReport.CustomerNo := Cust.”No.”;
    MyReport.NoOfIterations := 0;
    MyReport.RUN;

    More code, much more readable though.

    Regarding adding parentheses to function calls, I agree completely.

  5. This feature actually caused me an insufficient memory error. I had a procedure called SetSubstitutedOverride, which accepted a Boolean value called Override. The procedure was the type of which you speak, that had a single line assign to a global variable (in this case called SubstitutedOverride). I mistakenly wrote this code inside the procedure:

    SetSubsitutedOverride := Override;

    Notice I am calling the procedure, not the global variable. What I really wanted was:

    SubstitutedOverride := Override;

    The logic error caused by this typo (which would not normally compile, except for this feature) had the procedure calling itself recursively with no terminating condition. Nothing like blowing up the call stack.

    Unfortunately this code was only called under some rare circumstances, so it was a tough one to track down. Fun times. Just something to watch out for!

Leave a Reply