Evolving the Clarion Language

Nuts and bolts of the language changes made for .NET

<July 2008>
SuMoTuWeThFrSa
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

News

Current news on the nuts and bolts of the language changes made for .NET

Navigation

Subscriptions

Clarion# and Generics

We quietly slipped support for Generics into Clarion# in the last public release.  We hadn't completely finished with testing and documentation so we didn't make a lot of noise over it, but it is a very powerful new feature.

Generics provide you a facility for creating high-performance data structures because internally they are specialized by the compiler based on the types that they use.  Generic types can be defined in one language and used from any other .NET language. Generics provide the solution to a limitation in earlier versions of the Common Language Runtime in which generalization is accomplished by casting types to and from the universal base type Object. By creating a generic class, you can create a collection that is type-safe at compile-time.

Generic classes encapsulate operations that are not specific to any particular data type. The most common use for generic classes is with the collections like linked lists, hash tables, stacks, queues, trees and so on, where operations such as adding and removing items from the collection are performed in more or less the same way regardless of the type of the data being stored.

The best way to understand what generics can do for you is to study some Clarion# code. For example, the .Net System.Collections.Generic.List<T> requires you to specify a single value that describes the type of item the List<T> will operate upon. Therefore, if you wish to create three List<> objects to contain strings, integers and Person objects, you would write the following:

myStringList        List<string>
myIntList            List<Int32>
myPersonList      List<Person>
mp                    Person
    CODE
  myStringList = new List<string>()
        myStringList.Add('Joe')
        myStringList.Add('Jane')
  myIntList = new List<Int32>()
        myIntList.Add(2)
        myIntList.Add(3)
        myIntList.Add(4)
  myPersonList = new List<Person>()
        Loop i# = 1 to 5       
            mp = new Person()
            mp.Name = 'Joe' & i#
            myPersonList.Add(mp)
        End           

Once you have your data in your generic List you can display it with one line of code, for example:

self.dataGridView1.DataSource = self.myPersonList          ! bind to a DataGrideView
self.list1.DataSource = self.myPersonList                         ! bind to a Clarion List control
       
Developers can create classes and structures just as they normally have, and by using the angle bracket notation (< .. >) they can specify type parameters. When the generic class declaration is used, each type parameter must be replaced by a type argument that the user of the class supplies.  Support for Generics also opens the door for use of all of the .Net library as well as some very useful 3rd party libs and components.

posted Wednesday, April 16, 2008 7:08 PM by Robert Zaunere with 1 Comments

Clarion# Language features
In the early days of the Clarion# beta we had an ongoing discussion in the news groups focused on what changes we could make to Clarion# syntax to make it easier to read and write code. We've been busy implementing and testing those changes and we'll deliver them to you in the next release sometime next week.

Here is what's coming up:

We have removed the requirement to use & to declare a reference to an object in the data section. So instead of writing;

myString &String

you'll just write -
myString String

The & operator is still required when you want to declare a reference to a value type.  Value types are known as simple or primitive types and they include types such as Byte and Long, and by default, they are passed by value. Also GROUP, QUEUE, FILE, and ANY will require the & operator to declare as a reference.  But a reference type can be declared without the & and if the declaration doesn't have any parameters then the object will not be instantiated.

MyClass.P2 PROCEDURE()
A     MyCollection     ! just a declaration requires explicit instantiation
B     MyClass()        ! calls the default constructor
   CODE

This also means that you will use = operator for all reference types where now &= is currently required. For example:

Aa System.ICloneable
Bb System.ICloneable
CODE
Aa = Bb       ! whereas in the current version we write Aa &= Bb

That means we no longer have any need for the := operator, so its now removed from the Clarion# language.

However the &= operator is still needed to work with references to value-types (LONG, SHORT, DATE, GROUP, QUEUE, FILE, etc.)

Another change that was requested and implemented; no more automatic instantiation of objects, in other words all reference types are implicitly a TYPE.

Aa CLASS,TYPE

END
is now equivalent to:
Aa CLASS

END

The reasoning for this change was well explained by Dave Harms in a ClarionMag article which you can read here: http://www.clarionmag.com:8080/cmag/v9/v9n12instantiation.html

Automatic disposal of objects:
Since we now assign null to objects there is no sense to automatically call DISPOSE. Now it's the user's responsibility to create an object instance and thus it's user's responsibility to call DISPOSE if it's needed.

A word on constructors and declarations:

s     System.String('abc')
b     bool(True)

the compiler will generate for you as:
s = new String("abc")
b = new bool(true);

Another example to make this very clear:
S     System.String() ! parentheses means calling the default constructor
S     System.String  ! no parentheses so just a declaration without calling any constructor

With the described changes, given this code snippet:
A Aa
B Aa
CODE
A = B  

The statement A=B means assigning a reference.

So if the = operator is used to assign a reference, how do you copy content from one object to another?  Easy to do and required no language changes, the deep assignment operator :=: can be used for copying of content between like objects.

We have also introduced a new attribute AUTODISPOSE. If you mark a declaration with AUTODISPOSE then DISPOSE is called automatically on exit from the scope.

ZERO based indexes
We are changing Clarion# to use zero based indexes for all arrays and collections. But FILEs and QUEUEs will still use 1-based indexes. The rationale behind this change is that this makes it easier to work with the core Framework objects, 3rd-party .Net libraries, shared libraries you may write, as well as make it easier to translate code samples from C# or VB.

For those of you who have Clarion#, and those who soon will, we have also been looking into adding some features that will make it very easy to pass data back and forth from Clarion# and Clarion 7, so you'll be able to easily work side-by-side, .Net and Win32  Of course that can be done now but the idea is to make it much easier.

We have also been refining some of the UI features in the C7 RTL, and I'll post a blog on those changes later this weekend.

posted Friday, January 25, 2008 9:06 PM by Robert Zaunere with 7 Comments

WinForms and Threads
If you've done any programming in .Net, you're probably aware that accessing UI controls from a thread that didn't create the controls is a big no-no. One of the golden rules of using Winforms and Threading is that you don't touch anything created on one thread in another one.  

But not everyone is aware that neither ADO.NET nor Winforms are thread safe. Plainly put, you can’t update a WinForm control from a callback or from another thread, and you need to ensure that ADO.Net objects are not touched in multiple threads at the same time, it’s not always very easy. Writing multi-threaded code that violates these rules can seem to work perfectly fine while testing on your machine, but might not work on the machine sitting next to it, or maybe it works on Monday but not on Tuesday...

On MSDN you can find this statement from Microsoft:
"Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible as well, including race conditions and deadlocks. It is important to ensure that access to your controls is done in a thread-safe way."

And if you read a bit further you'd find this advice from Microsoft:

"When you use multithreading of any sort, your code can be exposed to very serious and complex bugs. For more information, see Managed Threading Best Practices before implementing any solution that uses multithreading. "

So what does this mean for a Clarion developer?  After all every Clarion program is multi-threaded, in fact most are seriously multi-threaded. Well those of you who were part of the EA program for Clarion 6 surely remember the problems we ran into when you started opening lots of MDI windows on separate threads in a tight loop; the result was a deadlock or a GPF. We reproduced the problem in a small Visual C++ program and opened an incident with Microsoft.  The test code we submitted would reliably crash the OS system kernel.  We were quite pleased to submit the bug report in anticipation of a quick bug fix, thus solving the problem our developers were running into.  

But it was not to be, our bug report was passed up the chain of support within Microsoft and finally reached the developers that work on the OS kernel.  At long last we thought, now we'll see it fixed.  But the problem was deemed too complex and risky to fix.  At that point Microsoft acknowledged the problem and told us that the documentation for the API that we used to create MDI windows on their own thread, an API that had been available forever, would be changed to state that it was not thread safe.  That made for a gloomy day in normally sunny South Florida.

So we were left on our own and it was time to make a decision, we could have chosen to either (a) tell our developers we were going to change our documentation to match the new Microsoft documentation and state that threaded MDI operations were not thread safe and should be avoided, or (b) find a way to fix the problem ourselves.  We chose (b), and through a combination of complex modifications to the RTL, new language functions, helper classes and template code, we succeeded.  Clarion Win32 programs can start new threads as fast as they want, they can communicate across threads, update the UI on other threads, and in general do about anything needed to get the job done.

But let’s get back to Winforms and threading.  Since its common knowledge that WinForms are not thread safe what's a Clarion developer going to do in .Net?  Well the answer from Microsoft would be to use threads very, very carefully, if at all.

From our side of the field there are some obvious choices, we could wrap all access to WinForms in the same fashion as we did for Clarion 6, or we could come up with something new that satisfied the needs of Clarion developers while avoiding the pitfalls of a single threaded UI model like WinForms.

There are two primary reasons why we Clarion developers like to use threads; performance related issues, we like to create responsive applications that don't put the user to sleep waiting for some report or process to complete, and secondly, we like to have multiple record buffers available to us.

Before I go any further let me make one thing crystal clear, you absolutely can write multi-threaded WinForm applications with Clarion.Net.  The Start command is implemented, and so is the THREAD attribute, so you can happily create your multi-threaded applications in the same fashion as Clarion 6 (just with a bit more care). So with threading support already implemented in the Clarion.Net runtime we could have stopped right there as it satisfies both of our primary reasons to use threads.

But we didn’t stop there, you have a new option available in Clarion.Net; you can apply the TYPE attribute to a FILE! 
The TYPE attribute is already supported for the GROUP, QUEUE and CLASS structures, so why not a FILE structure? Its more exciting then it sounds, it opens up all kinds of opportunites.

In Clarion.Net the TYPE attribute on a FILE allows you to create instances of a FILE, as many instances as you like, and each instance gets its own Record Buffer.  That means you can write code that opens multiple WinForms on the same thread, yet each "window" can have its own record buffer.  

Clarion developers can have the best of both worlds, i.e. you can Start() as many threads as you need, and those threads can use threaded files, and you have the option to work with files on a single threaded UI.  Or to put it another way, you can open multiple Browses on the same “typed” FILE, then open multiple Forms to update the Browses, each bit of code can work with a unique record buffer, and you can do it all on a single thread.

The use of typed files will be one of the options the .Net templates make available to you.  Working with a FILE with the TYPE attribute is no different from one without it, aside from the bit of code to create a new instance of the FILE.  However it does allow you to work safely and effectively within a single threaded UI.

posted Wednesday, November 15, 2006 1:06 PM by Robert Zaunere with 5 Comments

Powered by Community Server, by Telligent Systems