Wiki

Porting wxWidgets (wx.NET) C# source file to cobra

The .NET wrapper library (WX.Net) for  wxWidgets is an interesting case for Cobra since it is one of the few .NET libraries that uses a lowercase namespace.

Consequently there are some complications with persuading Cobra to work with it conveniently.

see Cobra differences from C#

Heres a process for C# generally with some notes re wx.NET generated from converting wx.NET sample file ListView.cs.
(See ListView.cs and converted ListView.cobra attachment files at end of this page.)

1 Take .cs file, rename to .cobra file.

2. Change multi-line comments from multiple // or /* */ bounded to be /# #/ bounded.
Change single line comments to use leading '#'

Remove extraneous separator line comments between method calls

// ------------------------------

3. Remove trailing ';' from each line they occur on

4. Fixup blocking and indentation.

Remove all '{' and '}' indicating start and end blocks from source.
Ensure remaining blocks are all correctly (equally) indented and that indentation uses either all spaces or all Tabs and that the indents are in multiples of either 4 spaces or 1 tab.

5. Fix 'using' statements

'using' -> 'use

Remove any lines for

using System
using System.Collections.Generic
using System.IO
using System.Text

as cobra includes these automagically

Change any other lines from

'using xxxx;' to 'use xxxx'

You also need to specify to use the C# wrapper library/namespace for wxWidgets ('wx').

Before 'use System.Drawing' add a 'use .. from line' for wx.NET

use wx from "wx.NET"
use System.Drawing

or add an explicit compiler directive ref line and a 'use wx' line

@ref "wx.NET"
        ...
use wx
use System.Drawing

6. Namespace decl

Namespaces in cobra need to start with an upcased letter. Remove any 'wx.' prefix from namespace line ;

'namespace wx.Something' to 'namespace Something'

7. Correct any Enum definitions.

After applying the above its basically removing trailing ',' and ensuring indentation of enum items is the same e.g.

enum Cmd { About, Quit, Dialog }

->

enum Cmd
    About
    Quit
    Dialog
enum ID_CONTROLS  {
    ID_RADIO_ORIENT = 5999,
    ID_CHK_SHOWIMAGES,
    ID_BTN_NEXT_PAGE,
    ID_NOTEBOOK
}

->

enum ID_CONTROLS
    ID_RADIO_ORIENT = 5999
    ID_CHK_SHOWIMAGES
    ID_BTN_NEXT_PAGE
    ID_NOTEBOOK

8. Fix class declaration syntax

Change lines like 'class X : Y' to 'class X inherits Y'

9. Change any class instance attributes/fields to be prefixed with 'var'

change type and accessmodifier to cobra forms

    <Type> name = <init> ;
    -->
    var name as <Type> = <init>

10. Fixup class constructor definitions

For initializer/constructor change lines like

public ClassName(params,...) : base(baseParams,...)

to

    cue init(params, ...) is public
        base.init(baseParams,...) 

Within the params list correct type declaration syntax from C# to cobra

	[<accessModifier> ...] <Type> name, 
	    -> 
	name as <Type> [is <accessModifier>, ...],

public is default accessModifier so can leave that off

e.g.

    public ListViewFrame (string title, Point pos, Size size) : base(title, pos, size)
           ->
    cue init(title as String, pos as Point, size as Size ) is public
        base.init (title, pos, size)

11. Remove any uses of 'new' to construct a class instance,

instead just make a call to the class type passing any initializer args, i.e just remove 'new'
e.g.

	menuFile = new Menu()   -> menuFile = Menu()
        new Point(10, 100)      -> Point(10, 100)
        new Size(650,340)	-> Size(650, 340)

For classes that construct delegates (take method names) prefix the methodname with ref,

methodNames must start with a lowercase letter and are prefixed by 'this.' or just '.' so change the methodName accordingly

e.g. new EventListener( OnAbout ) -> EventListener( ref .onAbout )

12. Methods:

Prefix methods with def.
Change methodnames to start with a lowercase letter,
Change param definitions to cobra form.

[<accessModifier> ...] <Type> name, -> name as <Type> [is <accessModifier>, ...],

Cobra methods by default return void and are public so if the C# code specifies public void you can just delete those words.

Also, if a method has no parameters then the empty trailing () can be left off.

Note builtin types:

C# string -> String
C# object -> Object

Theres a twist though; wx.NET also defines an Object (wx.Object) so that if you just declare something of Type Object theres a resolution ambiguity

message is 'Ambiguous reference "Object" found in namespaces "System" and "wx"'

so you have to either rely on the dynamic typing or resolve the ambiguity by specifying the namespace to use

e.g.

    public void OnAbout( object sender, Event e )
	        ->
    def onAbout(sender as System.Object, e as Event)  
    # OR def onAbout(sender, e as Event)  # untyped arg defaults to dynamic

    # no param method
    public override bool OnInit()
           ->
    def onInit as bool is override 
    # or def onInit as bool is public, override # explicit

13. Calls to methods, properties and attributes/fields.

Instance method names, properties and fields are called with a prefix of 'this.' or just '.'
and they all must be named starting with a lowercase letter so these calls and settings
must be modified accordingly.

e.g.

    menuFile.AppendWL(...   -> 	menuFile.appendWL( ...
    CreateStatusBar()       -> .createStatusBar # or this.createStatusBar

Similarly with properties and fields

    TextCtrl = new TextCtrl(this, ...   -> 	.textCtrl = TextCtrl(this, ...
    MenuBar = menuBar               -> 	.menuBar = menuBar
    Log.SetActiveTarget( textCtrl ) -> 	Log.setActiveTarget(.textCtrl) # static class

If a method takes no args then any empty trailing () on a method call can/should be left off.

14. Property definition. Depending on the property use, prefix properties with :

  • get - readable property only
  • set - settable property only
  • pro - gettable and settable

Change property names to start with a lowercase letter

15. Local variables declared and assigned on first use can usually be changed to remove the type definition (type inferred from the assignment) or can continue to be explicitly typed (if that compiles).

    ListItem info = new ListItem() 
      ->
    info = ListItem()     # or    info as ListItem = ListItem()

Heres a composite example

//  C#
    ListItem itemCol = new ListItem();
    itemCol.Text = "Second Column";
    itemCol.Align = ListCtrl.wxLIST_FORMAT_CENTER;
    itemCol.Width = 300;
    InsertColumn( 1, itemCol );
        -->
# Cobra
    itemCol = ListItem()
    itemCol.text = "Second Column"
    itemCol.align = ListCtrl.wxLIST_FORMAT_CENTER
    itemCol.width = 300
    .insertColumn(1, itemCol)

16. Fixup 'For' loops

for ( <Type> name = start ; name < stop; ++name ) 
        ->
for name as Type in start : stop : 1 # explicit or equally use shortcuts:
for name in start : stop : 1 
for name  in start : stop  # if step is one (1)
for name in stop           # if start is zero (0) and step is one (1)
    # same as for name in 0 : stop : 1

e.g

for ( int i = 0; i < 200; ++i ) -> for i in 0 : 200

17. Casting

Casts of form '(Type)name' become 'name to Type' e.g.

mf.AppendWL( (int)Cmd.About,... 
	->  
mf.appendWL(Cmd.About to int,...

Casts of form 'a as Type' can also become 'name to Type' or 'name to? Type' e.g

    ListEvent le = e as ListEvent; 
    -> 
    le = e to ListEvent 

18. String catenated with an expression (converted to string)

Put the expression (cobra converted) in the string inside [] e.g.

    "Value 1st field of selected item: " + le.Text  
             -> 
    "Value 1st field of selected item: [le.text]"

19. Adding eventHandlers

Cobra uses the listen statement to register event handlers where C# uses an override on the += operator. WxWidgets wraps method calls in an EventHandler delegate class instance.
Otherwise normal cobra mapping for method names and reference to methods (vs method calls)apply;
Methodnames in Cobra must start with a lower case letter and calls to this instance names

are prefixed with 'this.' or (easier) '.'

When translating from a 'use'd library namespace, calls to

Capcased methodnames are referenced in cobra with the first char lowercased,
Upcased methodnames are referenced with the first word lowercased

so

    EVENT += new EventListener( MethodName ) in C# becomes
    listen .EVENT, 	EventListener( ref .methodName ) 

    EVENT += new EventListener( EH_METHOD_NAME ) in C# becomes
    listen .EVENT, 	EventListener( ref .eh_METHOD_NAME ) 

e.g.

    ColumnClick += new EventListener( OnColumnClick )
    ItemSelect  +=  new EventListener( OnItemSelect )
    ColumnRightClick +=  new EventListener( OnColumnRightClick )
        ->
    listen .columnClick,    EventListener(ref .onColumnClick) 
    listen .itemSelect,     EventListener(ref .onItemSelect )
    listen .columnRightClick, EventListener(ref .onColumnRightClick)

WxWidgets menu action handlers can be done in C# using call to EVT_MENU.

EVT_MENU((int)MENU_ENUM_VALUE, new EventListener(MethodName));

the equivalent in cobra becomes

.evt_MENU(MENU_ENUM_VALUE to int, EventListener(ref .methodName))

e.g.

    EVT_MENU((int)Cmd.Quit,    new EventListener(OnQuit));
    EVT_MENU((int)Cmd.Dialog,  new EventListener(OnDialog));
    EVT_MENU((int)Cmd.About,   new EventListener(OnAbout));

->

    .evt_MENU(Cmd.Quit to int,    EventListener(ref .onQuit))
    .evt_MENU(Cmd.Dialog to int,  EventListener(ref .onDialog))
    .evt_MENU(Cmd.About to int,   EventListener(ref .onAbout))

20. Main method

'public void' is default, static is an accessmodifier which becomes 'shared' in cobra, C# attributes (MetaInformation) are denoted with 'has' e.g.

[STAThread]
static public void main()

to

def main is shared has STAThread 

21. Lowercased namespace names (as in wx.NET) used to disambiguate or otherwise explicitly

specify the namespace on types (inherits ..., as ....) as opposed to methods or constants
can (may/will) generate compile errors of the form:

error: Cannot find type for "wx.TYPE".
e.g. error: Cannot find type for "wx.Frame".

If such occurs the only recourse is to remove the explicit typing and rely on default handling.
e.g.

use wx from "wx.NET"
namespace SampleMinimal
    class MyFrame inherits wx.Frame
        # file.cobra(3): error: Cannot find type for "wx.Frame".

change to

use wx from "wx.NET"
namespace SampleMinimal
    class MyFrame inherits Frame

def onAbout(sender as System.Object, e as wx.Event )
change to
def onAbout(sender as System.Object, e as Event )

fileMenu as wx.Menu = wx.Menu()
change to
fileMenu = Menu()

Eventually it would be preferable if cobra became a little more flexible in these cases..


Other weirdnesses:

As of this doc date (Oct 2009) the wx.NET version and cobra seem to not be able to find some properties, specifically

Frame.Icon, .icon property -> no workaround.
Frame.StatusBar, .statusBar text property -> use method .setStatusBar(text) instead.

These and much of the above issues with recognising lowercased namespace references should be corrected (or at least improved) with the fix to ticket:184.

Attachments