Predefined Aspects

Elements comes with a set of predefined aspects that are used to expose language features without introducing new keywords to the language. All these aspects can be used directly by using them as an attribute.

Some of these aspects have an equivalent language-level syntax in one language and are only provided to bring the same feature to the others (but can be used on all thee languages for consistency, if so desired). Others are available via the aspect only.

Aspects that Expose Oxygene Language Features to RemObjects C

Notify

The Notify aspect can be used from C# and wift to add property change notification to a property, matching the notify modifier for Oxygene properties.

  • On .NET this will implement the INotifyPropertyChanging/INotifyPropertyChanged interfaces and trigger notifications.
  • On Cocoa this matches the Key-Value Observation logic NSObject implements.
  • On Java it implements addPropertyChangeListener and removePropertyChangeListener methods as described here.

Locked

The Locked aspect can be used in C# and Swift to make a method synchronized for thread-safe access, similar to the locked keyword in Oxygene. The aspect will lock the method on this/self.

Throws

Throws is used to add a Throws Definition for Java platform methods. While the Elements compiler does not enforce or use throws definitions on Java, this can be used to let the Java compiler know what things this method can throw, for example when using an Elements class library from a Java application. The aspect takes 1 parameter, which is the typeof() that the method throws. I can be applied multiple times,if the method throws more than one exception. Identical to the raises Oxygene keyword.

EventRaise

EventRaise can be used in C# and Swift to expose an externally facing "Fire" method for an event, making it possible to trigger an event from outside the class. It takes a Visibility parameter to define what access this raise method has. Oxygene has the raise keyword for events to achieve the same result.

class MyClass
{
    [EventRaise(Visibility.Public)]
    public event Action Done;
}

MyClass inst = new MyClass();
inst.Done(); // triggers Done, if assigned, or does nothing when there are no events.
class MyClass {
    [EventRaise(Visibility.Public)]
    public __event Done: Action
}

MyClass inst = MyClass()
inst.Done() // triggers Done, if assigned, or does nothing when there are no events.

Optional

Cocoa interface members can be marked as Optional with this aspect. A method marked as optional does not need to be implement when a class implements the interface.

SoftInterface

SoftInterface can be applied to an interface to make it "soft", so when a class that does not explicitly implement it gets assigned, Duck Typing is used to make it match. It is the equivalent of the soft keyword in Oxygene.

Category

Aspects that Expose Oxygene and Swift Language Features to C#

Lazy

Lazy is a property aspect that will make a property evaluate it's initial value when the property is first accessed. Lazy properties can be readonly or read/write. When a lazy property is written to before it's first read, the initial value is not evaluated at all. The accessors for Lazy properties are thread safe.

Lazy works on all four languages, but is not needed on Swift or Oxygene because these two languages have the lazy keyword to be used instead.

type
  MyClass = class
  private
    method LoadValues(): Dictionary<String, String>;
  public
    [Lazy] property Values: Dictionary<String, String> := LoadValues; readonly;
    // Values never gets created if it doesn't get used.
  end;
class MyClass
{
    private Dictionary<String, String> LoadValues() { ... }

    [Lazy] public Dictionary<String, String> Values { get; } = LoadValues();
    // Values never gets created if it doesn't get used.
}
class MyClass {
    private func LoadValues() -> [String:String] { ... }

    public lazy let Values: [String:String] { get; } = LoadValues();
    // Values never gets created if it doesn't get used.
}

Aspects that Bring .NET Functionality to Cocoa and Java

ToDo: Missing Conditional, Obsolete

Other Useful Aspects

NSApplicationMain / UIApplicationMain

These aspects can be used to introduce an Entry Point for a Cocoa application on iOS (UIApplicationMain) and OS X (NSApplicationMain). The aspect has to be applied to a class, and when found it inserts a new Main() method that will act as the application entry point and calls the NSApplicationMain/UIApplicationMain Cocoa method, passing the class as delegate.

namespace FirstOxygeneiOSApp;

interface

uses
  UIKit;

type
  [UIApplicationMain]
  AppDelegate = class(IUIApplicationDelegate)
  private
  public
    property window: UIWindow;
    method application(application: UIApplication) didFinishLaunchingWithOptions(launchOptions: NSDictionary): Boolean;
  end;

implementation

method AppDelegate.application(application: UIApplication) didFinishLaunchingWithOptions(launchOptions: NSDictionary): Boolean;
begin
  window := new UIWindow withFrame(UIScreen.mainScreen.bounds);
  window.rootViewController := new UINavigationController withRootViewController(new RootViewController);
  window.makeKeyAndVisible;
  result := true;
end;
namespace FirstCSharpiOSApp
{
    using UIKit;

    [UIApplicationMain]
    class AppDelegate : IUIApplicationDelegate
    {
        public UIWindow window { get; set; }

        public BOOL application(UIApplication application) didFinishLaunchingWithOptions(NSDictionary launchOptions)
        {
            window = new UIWindow withFrame(UIScreen.mainScreen().bounds);
            window.rootViewController = new UINavigationController withRootViewController(new RootViewController());
            window.makeKeyAndVisible();
            return true;
        }
    }
}
import UIKit

@UIApplicationMain class AppDelegate : IUIApplicationDelegate {
    public var UIWindow window?

    public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary) -> Bool {
        window = UIWindow(frame: UIScreen.mainScreen.bounds)
        window.rootViewController = UINavigationController(rootViewController:  RootViewController())
        window.makeKeyAndVisible()
        return true
    }
}

Mangle

The Mangle aspect can force a method to mangled on the Cocoa platform. Mangling is used to support overloading methods by their types, and by default, method names are only mangled if the method is overloaded. This aspect takes a boolean parameter to override the standard behaviour, for example to prepare a base class for overloading a method in its descendants.

DynamicProperty

Cocoa only aspect that can be applied to properties that don't have an actual implementation but still need to be callable. It's up to the class to intercept calls to this property to provide the implementation. Applying this attribute lets you call the property from the outside of the class.

Required

Defines a constructor to be "required", this matches the Silver "required" keyword for other platforms. Subclasses must implement a constructor like this.

Implements

Implements makes it possible to do explicit interface implementations on .NET when using the Silver language:

    @Implements(IEnumerable.Type, "GetEnumerator")
    func GetEnumeratorI() -> System.Collections.IEnumerator! {

        return self._dictionary.GetEnumerator()
    }

    public func GetEnumerator() -> IEnumerator<KeyValuePair<String, Object>>! {

        return self._dictionary.GetEnumerator()
    }

The first parameter is the type of the interface to implement. The second parameter is the method to implement. It will be matched by signature.

ToString

The ToString aspect is used to define a method as cross platform "ToString" method. On Cocoa this will be called when description is used, on .NET ToString and on Jva toString. This aspect does not rename the method, if it matches the existing platform method it makes sure it's properly override and public. If it doesn't it creates an additional method that calls this method.