mfp's two cents

...on Dynamics AX Development!

  • mfp's two cents

    What is new in X++ in AX7?

    • 0 Comments

    The X++ language has taken a huge leap ahead in AX7. Here is a list of some of the new capabilities:

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Attributes without specifying ”Attribute”

    • 0 Comments

    The naming convention in X++ (and C# by the way) is to postfix attribute classes' name with "Attribute". When using the attribute to decorate a class, it is a bit verbose to type in "Attribute" as it is apparent from the context, so now in X++ - just like in C# - you can skip the last part of the name.
    Example:

    class MyTestCase extends SysTestCase 
    {
        [SysTestMethodAttribute]
        public void testCase1()
        {
        }
    }  
     

    Is semantically identical to:

    class MyTestCase extends SysTestCase 
    {
        [SysTestMethod]
        public void testCase1()
        {
        } 
    }  

    Now, there is a difference in opinion on which one is best. One camp would argue that the shorter code is easier to read and write. Another camp would argue that referring to the same type in two different ways makes tooling (like refactoring tools, F12/Go to declaration and cross references tool) harder to implement. I agree with both, however, now the door is opened for this dual way of referencing and the tooling needs to follow suit. I'm in favor for the short notion.

     

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: String truncation

    • 2 Comments

    Consider this X++ code: 

    CustGroupId id = "012345678901234567890123456789"//30 chars long;  

    CustGroup custgroup;   
    custGroup.id = id;  
    custGroup.insert;   

    select custGroup 
       
    where custGroup.id == id;  

    The CustGroupID EDT is defined with a length of 20 characters. In AX 2012 the assignment in the very first line would truncate the string from 30 to 20 characters. The record would be inserted and selected again.

    In AX7 the CustGroupID EDT is being compiled as the CLR type: string. The consequence being that no truncation occurs in the first line. The truncation happens in the data base layer, as the column can only contain 20 characters. The most significant change is in the select statement. In AX7 no record will be found, as no record has an ID matching the 30-character long ID. 

    Actually; this also happens in AX2012 – when X++ code is compiled as CIL.

    Is this good or bad?

    I think it is primarily good. It is good - very good from a performance perspective. X++ is now compiled into CLR and is magnitudes faster than in AX2012. We could have injected a small check to validate and truncate every string upon assignment - at a quite dire cost. In the vast majority of cases the truncation isn't required - string lengths are already enforced, for example on the UI - so we opted for performance.

    The only issues we discovered by this was in automated testing - like unit tests, where test data defined in code contained too long strings. In reality an implementation problem already in AX2012 - but it didn't surface until now. Once you know this change in behavior, solving the relatively few issues aren't a big deal.

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Garbage Collection

    • 0 Comments

    In AX 2012 the runtime can either be the .NET CLR executing IL code, or the AX interpreter executing pcode. From a Garbage Collection point of view these two behaves extremely different. The difference is like night and day.

     

    In AX7 only the .NET CLR Garbage Collector is in play.

     

     

     

     

    Native AX interpreter

    .NET CLR

    Trigger

    Immediately – when reference count reaches zero.

    Indeterministic – usually when system is low on memory or idle. Can also be on demand.

    Performance

    Maintaining the reference counts is expensive. More info.
    Freeing memory in-proc is expensive, slowing down transactions, etc.

    Designed for minimal impact at runtime.

     

    Who cares?

    In most situations you don't have to care. The .NET GC will do what you expect. However; if you are dealing with any unmanaged resources, you have to pay attention.

    Locks in SQL is a typical unmanaged resource. If your logic uses the UserConnection class to obtain a lock in SQL, and you rely on the GC to release the lock (by aborting the user connection's transaction), then you will experience the lock not being released as you expect. In fact, you may notice it never gets released.

    The ReqReaderWriteLock class in AX2012 was doing exactly that. In AX7 this classes is now implementing the System.IDisposable interface. Consumers must ensure dispose() gets invoked. The using statement is handy here.

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Forms implementing interface

    • 1 Comments

    Forms can now implement interfaces.

     public class MyForm extends FormRun implements SysPackable
    {
    }    

     This is pretty cool, because:

    1. The compiler will validate that the interface is correctly implemented.
    2. No longer a need to use reflection, like hasFormMethod(), to determine if it is safe to call the method.
    3. No longer a need to downcast to object to invoke the methods. Now cast to the interface:

      var sysPackable = myFormRun as SysPackable;

      if (sysPackable) 
      {  
          sysPackable.pack();  
      }  

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Method signatures

    • 2 Comments

    This post is about one of the more subtle changes in AX7. AX7 uses the .NET runtime, aka CLR. This has some implications for method signatures. In the CLR a method's signature includes casing, parameters and return type. In AX2012 a method's signature was simply the method's name – case insensitive.

    Why is this important? If you change a method's signature, then all references to the method needs to be recompiled. Including those changes that appear harmless, like:

    • Fixing a casing issue in a method name, e.g. "somemethod" -> "someMethod".
    • Changing return type from void to <something>

    Here is an example, where I changed the casing of a method, that is being consumed by a test. I did NOT recompile the test before running it.

    Notice the System.MissingMethodException: Method not found: 'Void Dynamics.AX.Application.MyClass.myMethod()'. The CLR only knows of a method with all lower case.

    Optional parameters
    It is still safe to add and remove (unused) optional parameters. The X++ compiler uses CLR's method overloading, i.e. several methods with the same name and the variations of supported parameters are produced by the compiler.

    Lesson to learn
    Do not change a method's signature, unless you are willing (and able) to recompile all consumers.

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Inline variable declarations

    • 0 Comments

    What would you pay to be able to do this in X++?

    for (int i = 1; i <= n; i++)   
    {
    }    

    Or this:

    if (i > 0)    
    {
        int positiveInt = i;  
    }  

    Or this:

    if (applyInterestRate)
    {
        real rate = this.getInterestRate();  
        result = result * rate;  
    }  
    if (applyExchangeRate) 
    {  
        ExchangeRate rate = this.getExchangeRate();  
        result = result * rate.ExchangeRate;  
    }  

    Finally, we can:

    • Declare variables close(r) to where they are used,
    • Variables are scoped by the block in which they are declared, and
    • Variable names can be reused in another scope.

    The price: Join the ranks of AX7 developers!

    Note: Whenever you consider using inline variable declarations – consider extracting the code into a smaller method instead. Here is why.

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Const keyword

    • 5 Comments

    In AX7 X++ now supports the const keyword. Semantically it is identical to const in C#.

    In short; it allows you to define members on a class and variables in a method that can only be initialized during the declaration. The compiler will replace references to these constants with the literal value. In other words, the constant value must be known at compile time.

    This is a killer feature! It replaces most use cases of macros.

    void constsAreCool() 
    {
        #define.magicNumber("AX 2012");  
        const str MagicNumber = "AX7";  
        info(#magicNumber);  
        info(MagicNumber);  
    }  

    There are many benefits:

    1. IntelliSense in the editor.
    2. Support for "Go to definition" in the editor.
    3. Full control of the type for the constant.
    4. Faster compilation – macros are notorious hard for the compiler to handle.
    5. None of the macro idiosyncrasies – like the ability to redefine/override.

    Now when you couple this with public and static members, then you can create classes with constants to replace macro libraries.

    static class TimeConstants 
    {  
        static const public int DaysPerWeek = 7;  
        static const public int HoursPerDay = 24;  
        static const public int HoursPerWeek = TimeConstants::DaysPerWeek * TimeConstants::HoursPerDay;  
    }  

    It is best practice to use PascalCasing when naming const variables, regardless of if they are private, protected or public.

    Notice how the constants in the class are referenced:

    TimeConstants::HoursPerWeek  

    This is much clearer than macros:

    #TimeConstants
    int x = #HoursPerWeek  

    For example; you are no longer in doubt where the definition is coming from.

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Extension methods

    • 3 Comments

    Have you ever experienced a Microsoft provided class or table missing that vital method that would just make your life easier? If so, you might have been tempted to add it yourself using overlayering. And you surely have paid the upgrade price!

    You are about to be pleased. In AX7 X++ supports extension methods, similarly to C#.

    Suppose we want to add a fullName method to the DirPersonName table. Here is how you do it, without touching the DirPersonName table. Create this new class:

     

    static class MyDirPersonName_Extension 
    {  
        static public PersonName fullName(DirPersonName _person) 
        {  
            return strFmt('%1 %2 %3', _person.FirstName, _person.MiddleName, _person.LastName);  
        }  
    }  

    Things to remember:

    1. The class must be postfixed with "_extension".
    2. The class must be static.
    3. The extension methods must be static.
    4. The type of the first parameter determines which type is extended.

    Now you can enjoy your extension method:

    DirPersonName dirPersonName;  

    while select dirPersonName 
    {  
        info(dirPersonName.fullName());  
    }  

    Notice:

    1. When calling extension methods, you don't provide the first parameter – that gets inferred from the instance's type.
    2. If the extension method took any additional parameters – they (of course) needs to be provided.
    3. This doesn't break encapsulation. The extension method only has access to public fields and methods on the type.

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

  • mfp's two cents

    X++ in AX7: Readonly keyword

    • 0 Comments

    In AX7 X++ now supports the readonly keyword. Semantically it is identical to readonly in C#.

    In short; it allows you to define members on a class that can only be initialized in the declaration and in the constructor.

    class MyClass 
    {  
        readonly str identifier = "XYZ";  
        readonly str identifier2;  

        public void new(str _identifier) 
        {  
            identifier2 = _identifier;  
        }  

        public void foo() 
        { 
            // The field 'identifier2' is read only. A value cannot be assigned to it. 
            //identifier2 = "ABC";   
        }  
    }  

    The big question is "when to use it?" In my opinion the actual use scenarios are limited – simply because other language constructs are still missing.

    In X++ we still recommend the construct pattern and the newFrom pattern. These patterns recommend the new method to not have any parameters – readonly has little applicability, when the new method is parameter-less.

    So why do we prefer parameter-less new methods?

    1. It enables serialization of classes using the pack/unpack pattern – all classes extending RunBase are subject to this.
    2. It enables the extension framework and smart customizations.

    Once X++ supports getters/setters and method overloading (at least of the new method) – then readonly will become handy.

    If you have a good use scenario for readonly - please share in the comments section below.

     

    THIS POST APPLIES TO MICROSOFT DYNAMICS AX7 TECHNICAL PREVIEW; IS PROVIDED AS-IS AND CONFERS NO RIGHTS.

Page 1 of 22 (216 items) 12345»