2005/5/10

     
 

Metainfo Attributes

artefaktur

| Introduction | How to use | ClassLoader | Serialization | Reflection | Attributes | Mechanism |



One of the most interessting features of C# are Attributes, which works like a Compiler-Plugin interface. It can be used to implement some sort of Aspect-Programming features.


Content of this chapter:

   Attributes as extended Metainfo
     Sample
     Types Connected with MetaAttributes
       MetaAttributes
       MetaObjects
   Attributes as Metacompiler plugin
     Introduce Own Macros in ACDK declarations
   Attributes provided by acdkmc
     acdk.tools.mc.StringTagAttribute
     acdk.tools.mc.MethodAltNameAttribute
     acdk.tools.mc.McConfigAttribute



 Attributes as extended Metainfo

Which each declarative language element of ACDK Attributes can be connected.

 Sample


ACDK_CLASSATTRIBUTE(acdk.tools.mc.StringTagAttribute("Key1", "Val1"))
ACDK_CLASSATTRIBUTE(acdk.tools.mc.StringTagAttribute("Key2", "Val2"))
class TestClass
: extends acdk::lang::Object
{
  ACDK_WITH_METAINFO(TestClass)
public:
  ACDK_METHODATTRIBUTE(acdk.tools.mc.StringTagAttribute("Key3", "Val3"))
  void foo();
};

These Attributes can be listed at runtime:

void listAttributes(IN(acdk::lang::dmi::RMetaObject) mo)
{
  RMetaAttributeArray maa = mo->getMetaAttributes();
  System::out->println("MetaAttributes of element:");
  for (int i = 0; i < maa->length(); ++i)
  {
    RMetaAttribute ma = maa[i];
    System::out->print(ma->name);
    if (ma->value != Nil)
    {
      System::out->println(": " + ma->value->toString());
    }
    else
    {
      System::out->println(": Nil");
    }
  }
}

RObject obj = new TestClass();
RClass cls = obj->getClass();
listAttributes(cls);
RMethod method = cls->getDeclaredMethod("foo", new ClassArray(0));
listAttributes(method);

 Types Connected with MetaAttributes

The MetaAttributes has two API levels. On the underlying level MetaAttributes are connected with  acdk::lang::dmi::ClazzInfo and the other C based Meta database. On top of these API resides the higher API for reflection using acdk::lang::Class and the classes of the unit  acdk::lang::reflect.

 MetaAttributes

The class  acdk::lang::dmi::MetaAttribute has an key, used to identify the attribute, and a value.

 MetaObjects

The base interface for all classes, which holds the the MetaAttributes is  acdk::lang::dmi::MetaObject.
This interface is implemented by:
In future releases:


 Attributes as Metacompiler plugin


The attribute defined by ACDK_CLASSATTRIBUTE(...), ACDK_METHODATTRIBUTE(...) etc. are not hardwired constants, but represents a code fragmant in expressed in a tiny language ACDKScript. ACDKScript instruments normal ACDK classes via DMI. The class will be loaded via  ClassLoader.
The expression:
ACDK_METHODATTRIBUTE(acdk.tools.mc.StringTagAttribute("Key3", "Val3")) will be evaluated as:
new acdk.tools.mc.StringTagAttribute("Key3", "Val3");
which is in C++:
new acdk::tools::mc::StringTagAttribute("Key3", "Val3");

the resulting class in ACDK_CLASSATTRIBUTE(...) must be derived from  acdk::tools::mc::CodeAttribute and overwrite the apply(...) methods.
The acdkmc Metacompiler calls the apply methods after it parses the class definitions. The apply methods can:

 Introduce Own Macros in ACDK declarations

If you want introduce own macros, in the ACDK headers - for instance to insert method/member declarations - you have to follow following rules to avoid to confuse the ACDK Metacompiler acdkmc:
  • Start your define with ACDK_. ACDK_MYUNIT_DEF is OK.
  • Take care, that the comple define statement has ballance brackets:
    ACDK_MYUNIT_DEF(my text() continues) is OK, ACDK_MYUNIT_DEF(my "text)" continues) will confuse the acdkmc!

 Attributes provided by acdkmc

 acdk.tools.mc.StringTagAttribute

With the StringTagAttribute strings can be attached to an ACDK language element. ACDK_CLASSATTRIBUTE(acdk.tools.mc.StringTagAttribute("Key", "Value")) Will attach the string attribute "Value" under the "Key" at the next following class definition.

 acdk.tools.mc.MethodAltNameAttribute

For polymorphic methods (methods with same name, but different parameters) acdkmc will be generate alternative names with simply adding numbers to the name. These names can be used from DMI Client/Servers which doesn't support polymorphic methods.

Before numbering the methods, the methods with parameter with default values will split into multiple method definitions.

void foo(int i, int j = 1, int k = 2); 
int foo(IN(RString) str); 

The resulting methods definitions are:

void foo(int i, int j, int k); // no altname
void foo(int i, int j); // altname: foo1
void foo(int i); // altname: foo2
int foo(IN(RString) str); // altname: foo3
To control the alternative name of the methods the attribute acdk.tools.mc.MethodAltNameAttribute can be used:


class AClass
: extends acdk::lang::Object
{
  ACDK_WITH_METAINFO(AClass)
public:
  // version of next method with 3 parameters
  ACDK_METHODATTRIBUTE(acdk.tools.mc.MethodAltNameAttribute("fooWith3IntParams", 3)
  // CfgScript allows named parameters with the syntax:
  // ': NameOfParam = Value'
  ACDK_METHODATTRIBUTE(acdk.tools.mc.MethodAltNameAttribute(: altName = "fooWith2IntParams", 
                                                            : paramCount = 2))
  ACDK_METHODATTRIBUTE(acdk.tools.mc.MethodAltNameAttribute(: altName = "fooWith1IntParam", 
                                                            : paramCount = 1))
  void foo(int i, int j = 1, int k = 2); 
  
  ACDK_METHODATTRIBUTE(acdk.tools.mc.MethodAltNameAttribute("fooWithStringParam"))
  int foo(IN(RString) str); 
};

Via the DMI invoke method the methods are available via names fooWith3IntParams, fooWith2IntParams, fooWith1IntParam and fooWithStringParam.
For example in Perl:

my $aclass = acdk::new("AClass");
$aclass->fooWith1IntParam(42);
or in C++:

RObject obj = Object::New("AClass");
obj->invoke("fooWithStringParam", "ACDK");

In C++-calls, not using DMI, the alternative names are not available, but also not be necessary, because the C++-Compiler does the correct resolution of the polymorphic functions.

 acdk.tools.mc.McConfigAttribute

The Attribute acdk.tools.mc.McConfigAttribute - or with the short name McConfig - controls the ACDK MetaCompiler.
  • Enables or disable generating Metainfo for fields for a class or a single field.
  • Enables or disable generating Metainfo for methods for a class or a single method.

Sample:


namespace acdk {
namespace tools {
namespace aunit {
ACDK_DECL_CLASS(McConfigTest);

/**
  Dummy class to Test MetaCompiler with Attributes
*/

// don't generate Metainfo for methods or fields by default
ACDK_CLASSATTRIBUTE(McConfig(:GenMethod = false, :GenField = false)) 
class ACDK_TOOLS_TESTUNIT_PUBLIC McConfigTest
: extends acdk::lang::Object
{
  ACDK_WITH_METAINFO(McConfigTest)
public:
  int firstMember; // not metainfo will be available for firstMember
  
  // for the next field MetaInfo should be generated
  ACDK_FIELDATTRIBUTE(McConfig(:GenField = true)) // metainfo will be available
  int secondMember;

  void firstMethod() {} // not metainfo will be available for firstMethod

  // for the next method MetaInfo should be generated
  ACDK_METHODATTRIBUTE(McConfig(:GenMethod = true))
  void secondMethod(){} // metainfo will be available
};
} //namespace aunit
} // namespace tools
} // namespace acdk 



Classes which are marked with ACDK_WITH_METAINFO will have MetaInfo available. You can use McConfig as ClassAttribute to change this default behaivor. If by default metainfo for members and methods should be available, you can also use the pseudo-keyword 'foreign'
to mark a method or a field as unknown to the MetaCompiler.