Suppose you want to develop a large, complex application for Linox. The application is going to be multiprocess, perhaps distributed, and definitely has to have a GUI. You want to build this application fairly quickly, and you want it to be relatively bug free.
One of the first questions you might ask yourself is “What programming language and environment should I use?” C might be a good choice, but probably not for this project. It doesn't scale as well as you'd like, and the tools for doing multiprocess/distributed programming for C just aren't there. You might consider C++, but the language is fairly complex. Also, you and others have discovered from past experience that a fair amount of time goes into debugging subtle memory management problems.
There is an alternative, the Modula-3 programming system from Digital Equipment Corporation's Systems Research Center (SRC). Modula-3 is a modern, modular, object-oriented language. The language features garbage collection, exception handling, run-time typing, generics, and support for multithreaded applications. The SRC implementation of this language features a native-code compiler; an incremental, generational, conservative, multithreaded garbage collector (whew!); a minimal recompilation system; a debugger; a rich set of libraries; support for building distributed applications; a distributed objectoriented scripting language; and, finally, a graphical user interface builder for distributed applications. In short, the ideal environment for the type of application outlined above. Moreover, the system is freely available in source form, and pre-built Linux binaries are available as well.
The remainder of this article will touch on the pertinent features of the language and provide an overview of the libraries and tools.
One of the principal goals for the Modula-3 language was to be simple and comprehensible, yet suitable for building large, robust, long-lived applications and systems. The language design process was one of consolidation and not innovation; that is, the goal was to consolidate ideas from several different languages, ideas that had proven useful for building large sophisticated systems.
You can think of Modula-3 as starting with Pascal and re-inventing it to make it suitable for real systems development. Beginning with a Pascal-like base, features were integrated that were deemed necessary for writing real applications. These features fall roughly into two areas: those which make the language more suitable for structuring large systems, and those which make it possible to do “machine-level” programming. Real applications need both of these.
There are several features in Modula-3 that support structuring of large systems. First is the separation of interface from implementation. This allows for system evolution as implementations evolve without affecting the clients of those interfaces; no one is dependent on how you implement something, only what you implement. As long as the what stays constant, the how can change as much as is needed.
Secondly, it provides a simple single-inheritance object system. There is a fair amount of controversy over what the proper model for multiple inheritance (MI) is. I have built systems that use multiple-inheritance extensively and have implemented programming environments for a language that supports MI. Experience has taught me that MI can complicate a language tremendously (both conceptually and in terms of implementation) and can also complicate applications.
Modula-3 has a particularly simple definition of an object. In Modula-3, an object is a record on the heap with an associated method suite. The data fields of the object define the state and the method suite defines the behavior. The Modula-3 language allows the state of an object to be hidden in an implementation module with only the behavior visible in the interface. This is different than C++ where a class definition lists both the member data and member function. The C++ model reveals what is essentially private information (namely the state) to the entire world. With Modula-3 objects, what should be private can really be private.
One of the most important features in Modula-3 is garbage collection. Garbage collection really enables robust, long-lived systems. Without garbage collection, you need to define conventions about who owns a piece of storage. For instance, if I pass you a pointer to a structure, are you allowed to store that pointer somewhere? If so, who is responsible for de-allocating the structure in the future? You or me? Programmers wind up adopting such conventions as the explicit use of reference counts to determine when it is safe to deallocate storage. Unfortunately, programmers are not very good about following conventions. The net result is that programs develop storage leaks or the same piece of storage is mistakenly used for two different purposes. Also, in error situations, it may be difficult to free the storage. In C, a longjmp may cause storage to be lost if the procedure being unwound doesn't get a chance to clean up. Exception handling in C++ has the same problems. In general, it is very difficult to manually reclaim storage in the face of failure. Having garbage collection in the language removes all of these problems. Better yet, the garbage collector that is provided with the SRC implementation of Modula-3 has excellent performance. It is the result of several years of production use and tuning.
Most modern systems and applications have some flavor of asynchrony in them. Certainly all GUI-based applications are essentially asynchronous. Inputs to a GUI-based application are driven by the user. Multiprocess and multi-machine applications are essentially asynchronous as well. Given this, it is surprising that very few languages provide any support at all for managing concurrency. Instead, they “leave it up to the programmer”. More often than not, programmers do this through the use of timers and signal handlers. While this approach suffices for fairly simple applications, it quickly falls apart as applications grow in complexity or when an application uses two different libraries, both of which try to implement concurrency in their own way. If you have ever programmed with Xt or Motif, then you are aware of the problems with nested event loops. There needs to be some standard mechanism for concurrency.
Modula-3 provides such a standard interface for creating threads. In addition, the language itself includes support for managing locks. The standard libraries provided in the SRC implementation are all thread-safe. Trestle, which is a library providing an interface to X, is not only thread-safe, but itself uses threads to carry out long operations in the background. With a Trestle-based application, you can create a thread to carry out some potentially long-running operation in response to a mouse-button click. This thread runs in the background without tying up the user interface. It is a lot simpler and less error prone than trying to accomplish the same thing with signal handlers and timers.
Generic interfaces and modules are a key to reuse. One of the principal uses is in defining container types such as stacks, lists, and queues. They allow container objects to be independent of the type of entity contained. Thus, one needs to define only a single “Table” interface that is then instantiated to provide the needed kind of “Table”, whether an integer table, or a floatingpoint table or some other type of table is needed. Modula-3 generics are cleaner than C++ parameterized types, but provide much of the same flexibility.
|Designing Electronics with Linux||May 22, 2013|
|Dynamic DNS—an Object Lesson in Problem Solving||May 21, 2013|
|Using Salt Stack and Vagrant for Drupal Development||May 20, 2013|
|Making Linux and Android Get Along (It's Not as Hard as It Sounds)||May 16, 2013|
|Drupal Is a Framework: Why Everyone Needs to Understand This||May 15, 2013|
|Home, My Backup Data Center||May 13, 2013|
- Designing Electronics with Linux
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Dynamic DNS—an Object Lesson in Problem Solving
- Using Salt Stack and Vagrant for Drupal Development
- Validate an E-Mail Address with PHP, the Right Way
- Why Python?
- Linux Systems Administrator
- Tech Tip: Really Simple HTTP Server with Python
- Build a Skype Server for Your Home Phone System
- Dynamic DNS
25 min 43 sec ago
- Reply to comment | Linux Journal
1 hour 24 min ago
- Reply to comment | Linux Journal
2 hours 14 min ago
- Not free anymore
6 hours 16 min ago
10 hours 3 min ago
- Reply to comment | Linux Journal
10 hours 11 min ago
- Understanding the Linux Kernel
12 hours 26 min ago
14 hours 55 min ago
- Kernel Problem
1 day 58 min ago
- BASH script to log IPs on public web server
1 day 5 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi
It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?