Thursday 11 February 2016

X++ in AX7: The var keyword

This is the new language feature that is generating most discussions. Just like C# you can now use the var keyword when declaring variables. It has the exact same semantics, and any guideline you will find on how to use it in C# will also apply in X++.
 
In C# the var keyword was introduced to enable scenarios where declaring the type was impossible, near-impossible or irrelevant, like with anonymous types and generics. Writing less was naturally well received by a lot of developers, and the use of var blossomed. It is also a great topic for steering up a debate. There are lots of guidelines and opinions. They cover the entire range from one extreme: "Always use it, it makes code easier to read" to the opposite extreme: "Never use it, it makes code harder to read".
 
X++ does not support anonymous types or generics in AX7 - so the real need for the var keyword is not present - yet it is supported, and already heavily used. Like in C# the use of var is as strongly typed as when the type is explicitly provided.
 
Personally, I'm recommending using var in only two cases:
When the type is obvious.
In X++ there is a lot of repetition. The var keyword can help avoid some of this clutter while making the code easier to read, without any information gets lost to the reader.
For example:

MyClass myClass = new MyClass();  
In AX7 I would write:
var myClass = new MyClass();  


When the type is irrelevant.

Sometimes you don't care about the type. If you don't care the reader most likely doesn't either. 
For example:


ListEnumerator enumerator = myCollection.getEnumerator();
In AX7 I would write:
var enumerator = myCollection.getEnumerator();   



 There are a number of X++ specific reasons to not use var (i.e. doesn't apply to C#)

Limited support Visual Studio.

In the X++ editor in Visual Studio, you can use F12 to go to the declaration of a type. However, the X++ editor is still not as smart as the X++ compiler. At the time of this writing you are losing this drill through capability when not explicitly specifying the type of the variable. The same applies for IntelliSense – when using the var keyword, IntelliSense is not available (yet).
Higher risk of runtime errors.

Just like the C# compiler, the X++ compiler will determine the type from the assignment to the variable and enforce all the same rules and restrictions.

 So you might think that the use of var doesn't lead to more runtime errors. There is a catch in X++ - you should be aware of. The X++ compiler doesn't enforce any validation of method invocations on object or common. So if the X++ compiler determines the type to be object or common, then you lost your safety net. It is not always obvious.




Consider this code:

CustTable custTable = Xml2Record(xml);

custTable.someInvalidMethod(); // Compile error  

Using var, the code becomes:

var custTable = Xml2Record(xml);  

custTable.someInvalidMethod(); // No compile error, as Xml2Record() returns a common  

X++ in AX7: The var keyword

This is the new language feature that is generating most discussions. Just like C# you can now use the var keyword when declaring variables. It has the exact same semantics, and any guideline you will find on how to use it in C# will also apply in X++.
 
In C# the var keyword was introduced to enable scenarios where declaring the type was impossible, near-impossible or irrelevant, like with anonymous types and generics. Writing less was naturally well received by a lot of developers, and the use of var blossomed. It is also a great topic for steering up a debate. There are lots of guidelines and opinions. They cover the entire range from one extreme: "Always use it, it makes code easier to read" to the opposite extreme: "Never use it, it makes code harder to read".
 
X++ does not support anonymous types or generics in AX7 - so the real need for the var keyword is not present - yet it is supported, and already heavily used. Like in C# the use of var is as strongly typed as when the type is explicitly provided.
 
Personally, I'm recommending using var in only two cases:
When the type is obvious.
In X++ there is a lot of repetition. The var keyword can help avoid some of this clutter while making the code easier to read, without any information gets lost to the reader.
For example:

MyClass myClass = new MyClass();  
In AX7 I would write:
var myClass = new MyClass();  


When the type is irrelevant.

Sometimes you don't care about the type. If you don't care the reader most likely doesn't either. 
For example:


ListEnumerator enumerator = myCollection.getEnumerator();
In AX7 I would write:
var enumerator = myCollection.getEnumerator();   



 There are a number of X++ specific reasons to not use var (i.e. doesn't apply to C#)

Limited support Visual Studio.

In the X++ editor in Visual Studio, you can use F12 to go to the declaration of a type. However, the X++ editor is still not as smart as the X++ compiler. At the time of this writing you are losing this drill through capability when not explicitly specifying the type of the variable. The same applies for IntelliSense – when using the var keyword, IntelliSense is not available (yet).
Higher risk of runtime errors.

Just like the C# compiler, the X++ compiler will determine the type from the assignment to the variable and enforce all the same rules and restrictions.

 So you might think that the use of var doesn't lead to more runtime errors. There is a catch in X++ - you should be aware of. The X++ compiler doesn't enforce any validation of method invocations on object or common. So if the X++ compiler determines the type to be object or common, then you lost your safety net. It is not always obvious.




Consider this code:

CustTable custTable = Xml2Record(xml);

custTable.someInvalidMethod(); // Compile error  

Using var, the code becomes:

var custTable = Xml2Record(xml);  

custTable.someInvalidMethod(); // No compile error, as Xml2Record() returns a common  

X++ in AX7: Type declarations can be 80 characters

Since the first version of Axapta developers have suffered a limitation of 40 characters when defining types, like classes, tables, extended data types, and even when defining methods and fields.




 
This limit was at first completely removed, to the joy of us developers who could now come up with some really crazy method names.


However; it turned out certain subsystems in the Dynamics AX Visual Studio integration was breaking down under this. The compromise was a limitation of 80 characters - still plenty to be creative.




Just like that:




class MyClassShouldHaveAProperNameThatClearlyDescribesItsPurposeItIsOkIfItIsLooong 
{            
}


X++ in AX7: Finally and using

Finally, X++ got support for the finally statement. It has exactly the same semantics as in C#. This means that you can now write:




try
{
}   
catch
{
}    
finally
{
}     

  
The contents of the finally block is guaranteed to be executed - regardless of exceptions or transactions. It is typically used to clean up any usage of none-managed resources. And to make that construct even cleaner, you can use the using keyword for types implementing the


System.IDisposable interface.




using(var myObject = new MyObject())
{
    myObject.someMethod();
}  
 
This is short hand for:
var myObject = new MyObject();
try
{
    myObject.someMethod();
}
finally
{
    myObject.Dispose();
}  


One more thing…

Just like in C# the using statement can also be used to avoid providing fully qualified names when referencing .NET types. This means I can implement MyObject like this:






using System;
class MyObject implements IDisposable 
{            
    public void Dispose()
    {
    }
}     

X++ in AX7: Finally and using

Finally, X++ got support for the finally statement. It has exactly the same semantics as in C#. This means that you can now write:




try
{
}   
catch
{
}    
finally
{
}     

  
The contents of the finally block is guaranteed to be executed - regardless of exceptions or transactions. It is typically used to clean up any usage of none-managed resources. And to make that construct even cleaner, you can use the using keyword for types implementing the


System.IDisposable interface.




using(var myObject = new MyObject())
{
    myObject.someMethod();
}  
 
This is short hand for:
var myObject = new MyObject();
try
{
    myObject.someMethod();
}
finally
{
    myObject.Dispose();
}  


One more thing…

Just like in C# the using statement can also be used to avoid providing fully qualified names when referencing .NET types. This means I can implement MyObject like this:






using System;
class MyObject implements IDisposable 
{            
    public void Dispose()
    {
    }
}     

X++ in AX7: Type declarations can be 80 characters

Since the first version of Axapta developers have suffered a limitation of 40 characters when defining types, like classes, tables, extended data types, and even when defining methods and fields.




 
This limit was at first completely removed, to the joy of us developers who could now come up with some really crazy method names.


However; it turned out certain subsystems in the Dynamics AX Visual Studio integration was breaking down under this. The compromise was a limitation of 80 characters - still plenty to be creative.




Just like that:




class MyClassShouldHaveAProperNameThatClearlyDescribesItsPurposeItIsOkIfItIsLooong 
{            
}


X++ in AX7: Private and public members

Since the first version of Axapta, member variables in classes have been protected. In AX7 the default remains protected, however, you can now mark them as public or private.


Here is an example:


class MyClass
{    
    public int PublicMember;    
    private int privateMember;    
    int protectedMember; //Defaults to protected
    protected int explicitlyProtectedMember;
}    



You can access the public member using the same syntax as when accessing fields on Tables (or properties in C#). Notice the best practice is to use PascalCasing for public members – just like for fields on tables.




var myClass = new MyClass();
myClass.PublicMember = 42;  
 



There is still no support for getters and setters (like we know them from C#).

X++ in AX7: Private and public members

Since the first version of Axapta, member variables in classes have been protected. In AX7 the default remains protected, however, you can now mark them as public or private.


Here is an example:


class MyClass
{    
    public int PublicMember;    
    private int privateMember;    
    int protectedMember; //Defaults to protected
    protected int explicitlyProtectedMember;
}    



You can access the public member using the same syntax as when accessing fields on Tables (or properties in C#). Notice the best practice is to use PascalCasing for public members – just like for fields on tables.




var myClass = new MyClass();
myClass.PublicMember = 42;  
 



There is still no support for getters and setters (like we know them from C#).

X++ in AX7: Client/Server keywords

In AX7 all X++ code is running on the server tier. No exceptions. The compiler is ignoring client and server keywords.



When you come across any of these just delete them without a second thought:
  • Client and Server keywords
  • //AOSRunMode::xxx
  • xGlobal::ClientKind()
  • Dangling semicolons (but that is another story)

Similarly, if you stumble into any code that was taking the journey to the opposite tier to do some "magic" and then pack down the results in a container – consider refactoring the code.




The journey is not happening anymore, and it is pure overhead. Typically such methods are static methods named xxx_OnServer() or xxxClient().

X++ in AX7: Static members

You can now declare class member variables as static. The semantics are exactly the same as in C#; namely that all instances of the class will share the member, e.g. if one class sets the value, another class can get it.

Naturally; this should be used with care, but there are some really cool use cases, for example, implementing a singleton pattern in now much cleaner.

Example:
class MyClass
{  
    static MyClass singleton;

    public MyClass getInstance()
    {
        if (!singleton)
        {
            singleton = new MyClass();
        }
        return singleton;
    }
}     

In previous versions of AX you could achieve similar behavior through the SysGlobalCache classes. The main functional difference between the two is that you can flush the SysGlobalCache classes.




This is especially useful during test execution, where the test framework is automatically flushing the caches between each run to avoid state leaking from one test to another.




Static members will not automatically be flushed – you can of course create a flush() method yourself and hook it up to the SysTest::postInvokeTearDown() event.

X++ in AX7: Static members

You can now declare class member variables as static. The semantics are exactly the same as in C#; namely that all instances of the class will share the member, e.g. if one class sets the value, another class can get it.

Naturally; this should be used with care, but there are some really cool use cases, for example, implementing a singleton pattern in now much cleaner.

Example:
class MyClass
{  
    static MyClass singleton;

    public MyClass getInstance()
    {
        if (!singleton)
        {
            singleton = new MyClass();
        }
        return singleton;
    }
}     

In previous versions of AX you could achieve similar behavior through the SysGlobalCache classes. The main functional difference between the two is that you can flush the SysGlobalCache classes.




This is especially useful during test execution, where the test framework is automatically flushing the caches between each run to avoid state leaking from one test to another.




Static members will not automatically be flushed – you can of course create a flush() method yourself and hook it up to the SysTest::postInvokeTearDown() event.

X++ in AX7: Client/Server keywords

In AX7 all X++ code is running on the server tier. No exceptions. The compiler is ignoring client and server keywords.



When you come across any of these just delete them without a second thought:
  • Client and Server keywords
  • //AOSRunMode::xxx
  • xGlobal::ClientKind()
  • Dangling semicolons (but that is another story)

Similarly, if you stumble into any code that was taking the journey to the opposite tier to do some "magic" and then pack down the results in a container – consider refactoring the code.




The journey is not happening anymore, and it is pure overhead. Typically such methods are static methods named xxx_OnServer() or xxxClient().

X++ in AX7: Static classes

You can now mark a class as static.


static class MyClass
{
}  



It will not be possible to create instances of this class. This is useful for classes providing static methods only – like the Global class.

X++ in AX7: Static event subscription

In AX2012 we introduced events. Unfortunately, we got the subscription part of static events upside down. In the meta model you were forced to change the publisher when adding a subscriber.


This resulted in an intrusive customization. And thus defeats most of the purpose.




In AX7 this has been corrected. You can now subscribe to events using the SubscribesTo attribute.
Extending the singleton example from my previous post, we can now implement the flush method.




class MyClass
{  
    static MyClass singleton;

    public MyClass getInstance()
    {
        ...
    }

    [subscribesTo(classStr(SysTest), delegateStr(SysTest, postInvokeTearDown)]
    public static void flush()
    {
       singleton = null;
    }
}     




Note: Subscribing to the SysTest.postInvokeTearDown event to flush a singleton is overkill. This event will fire for all tests, and thus slow down every test execution (a little bit). An alternative implementation could be to use dynamic event subscription to only hook up the event as needed. Dynamic event subscriptions work in exactly the same way as in AX2012.

X++ in AX7: Static event subscription

In AX2012 we introduced events. Unfortunately, we got the subscription part of static events upside down. In the meta model you were forced to change the publisher when adding a subscriber.


This resulted in an intrusive customization. And thus defeats most of the purpose.




In AX7 this has been corrected. You can now subscribe to events using the SubscribesTo attribute.
Extending the singleton example from my previous post, we can now implement the flush method.




class MyClass
{  
    static MyClass singleton;

    public MyClass getInstance()
    {
        ...
    }

    [subscribesTo(classStr(SysTest), delegateStr(SysTest, postInvokeTearDown)]
    public static void flush()
    {
       singleton = null;
    }
}     




Note: Subscribing to the SysTest.postInvokeTearDown event to flush a singleton is overkill. This event will fire for all tests, and thus slow down every test execution (a little bit). An alternative implementation could be to use dynamic event subscription to only hook up the event as needed. Dynamic event subscriptions work in exactly the same way as in AX2012.

X++ in AX7: Static classes

You can now mark a class as static.


static class MyClass
{
}  



It will not be possible to create instances of this class. This is useful for classes providing static methods only – like the Global class.

X++ in AX7: Internal keyword

internal is a new keyword in X++. It has the same semantics as in C#.


When you mark a class or method as internal, then it can only be accessed from within the model where it is defined.




internal class MyInternalClass
{
    internal void myInternalMethod()
    {
    }
}



Notice, you can define internal methods on public classes too.

X++ in AX7: Internal keyword

internal is a new keyword in X++. It has the same semantics as in C#.


When you mark a class or method as internal, then it can only be accessed from within the model where it is defined.




internal class MyInternalClass
{
    internal void myInternalMethod()
    {
    }
}



Notice, you can define internal methods on public classes too.