Archive for the '.NET' Category

04
Sep
06

Connections, Shared Space and Autonomy

Patterns

It’s interesting how simple patterns reappear in the most unexpected places, and how they often the similarity goes unnoticed. For example, take this simple pattern condensed from A Pattern Language.

179. Alcoves**

. . . many large rooms are not complete unless they have smaller rooms and alcoves opening off them. . .

* * *

No homogeneous room, of homogeneous height, can serve a group of people well. To give a group a chance to be together, as a group, a room must also give them the chance to be alone, in one’s and two’s in the same space.

This problem is felt most acutely in the common rooms of a house—the kitchen, the family room, the living room. In fact, it is so critical there, that the house can drive the family apart when it remains unsolved. . . .

In modern life, the main function of a family is emotional; it is a source of security and love. But these qualities will only come into existence if the members of the house are physically able to be together as a family.

This is often difficult. The various members of the family come and go at different times of day; even when they are in the house, each has his own private interests. . . . In many houses, these interests force people to go off to their own rooms, away from the family. This happens for two reasons. First, in a normal family room, one person can easily be disturbed by what the others are doing. . . .Second, the family room does not usually have any space where people can leave things and not have them disturbed. . . .

To solve the problem, there must be some way in which the members of the family can be together, even when they are doing different things.

Therefore:

Make small places at the edge of any common room, usually no more than 6 feet wide and 3 to 6 feet deep and possibly much smaller. These alcoves should be large enough for two people to sit, chat, or play and sometimes large enough to contain a desk or table.

Give the alcove a ceiling, which is markedly lower than the ceiling height in the main room. . . . (Alexander 1977b)

CLR – Multiple Languages

Reading this for a second time invoked a number of thoughts. The first was to relate this pattern to virtual machines, like the .NET CLR. In this first example, I was thinking of how they serve as a nexus for different programming languages. The CLR (or JVM) itself is much like the room at the center, and the languages the alcoves. Much like height of ceilings, no one language can meet the needs of all developers or development tasks. Different developers require languages of different complexity. More importantly, different development tasks require languages of different complexity (and possibly developers of different complexity too).

But developers are best as a community to avoid solving the same problems more times than necessary. Without a central (intermediary) language, it’s not possible to share libraries seamlessly, and communication is more difficult. The CLR serves as a common center. IL establishes sets a level of maximum complexity, and each language retains some autonomy while enjoying the benefits of the CLR.

It’s worth noting that the CLR must be more complex than all other languages by nature of having to support the primitives of those languages. In principle, languages using the CLR could be more complex, but they would have to dumb down their behaviors and fake that complexity within IL. But by doing so, that complexity would become inaccessible to other language consumers. Ideally, you want the IL to support the same or greater level of complexity.

I use the CLR as the example here, because Microsoft was first to popularize the concept, but the JVM is just as capable of this. There are some minor differences, but I won’t waste time (today) trying to discover which is better. Instead, I’d prefer to move on to a similar example that the JVM popularized.

JVM – WORA

One goal of the JVM was to unite multiple operating systems. The concept was Write Once Run Anywhere (WORA). You can see the similarity, where the JVM acts as a center. Operating systems would share applications, not just libraries, and communication would be less difficult. However, like language interoperability you’d want the central room to have the highest ceiling, because otherwise you would be limited by the JVM.

But whereas writing a high level, nonuser language like Java bytecode or IL relaxed many constraints of design, due to not having to worry much about the user, multiple operating system support did not have the same advantage.

For simple actions that were already common to operating systems, the process worked well. For more complicated areas, like user interfaces, where different operating systems had significantly different implementations, it did not. Java has tried very hard to address this, but while Java 6 is set to address many outstanding UI issues, Microsoft is set to release a new UI framework. Beyond this, what about the unique UI features of the OS X, both today and tomorrow? In order to be the center for all operating systems, Java would need to be an operating system, bigger and more complex than all others.

Of course, a more practical approach is to rely upon WORA only in application domains that rely mostly upon simple common features. In these areas, the JVM serves portability needs very well.

It’s interesting to note that such portability is as possible with the CLR. Mono for example runs most .NET applications that don’t make use of user interface libraries tightly coupled to the Windows operating system. But cross platform user interface libraries are just as possible under the CLR as under the JVM. GTK# is an excellent example of one. But of course, the same difficulties with taking advantage of OS specific features arise, but if portability is more important than the latest features then this is an option.

It’s also interesting to note that other operating systems can have direct support of their own, like with Cocoa#. The Java community has generally discouraged this type of development, but it is just as possible under the JVM.

Integrated Development Environments – Language Workbenches

A few weeks ago, I was writing about the importance of metadata. Serendipitously, a reader of another post linked me into an essay of Martin Fowler’s that tuned into what I’ve been thinking about for a while, but haven’t quite so eloquently written. To sum it up, Martin talks about “language workbenches”. He defines a workbench as:

  • Users can freely define new languages, which are fully integrated with each other.
  • The primary source of information is a persistent abstract representation.
  • Language designers define a DSL in three main parts: schema, editor(s), and generator(s).
  • Language users manipulate a DSL through a projectional editor.
  • A language workbench can persist incomplete or contradictory information in its abstract representation.

Since that might not make too much sense out of context, I’ll sum it up. The idea is the workbench maintains a central abstract representation of code. Editors, instead of being simple text editors interact with this representation. The overall user experience could be similar or the same, but the underlying mechanics totally different.

This is however, another example of the alcove pattern, where the workbench is defining a high ceiling abstract representation, but you can use multiple editors and sublanguages to satisfy the needs of individual domains. This takes the inter project cross language compatibility established by the JVM/CLR and extends it to intra project activities.

There’s more to this topic however, which I will cover in another post.

Other examples

There are plenty of other examples of this pattern. Operating Systems themselves are a good example. Applications need their own process space, but they also need a standard system for communication with hardware, other software, and the user.

Pieces of networks are good examples as well. The network itself isn’t a very good example, but anywhere that users have both a private and shared space, such as sites like digg and reddit are good examples.

This is an important concept to remember in designing network applications because it’s important not only that you give users a place to communicate, but also that you allow them enough isolation that they don’t wander off to their own rooms, or feel constrained within the one room.

13
Aug
06

Functional Programming in Java, C#, VB.NET? Soon.

I’ve been doing a lot of reading lately, and lot of it has been about functional programming. There are many well known writers out there with quite a bit to say on the topic. For example, Steve Yegge and Paul Graham talk about the virtues of functional languages a lot. What I don’t understand is why neither has even once mentioned C# 3.0. They and many others talk a lot about Ruby, and how important functional programming is there, and they are right. But I can’t understand how someone who values functional programming so much can ignore the functional features in C# 3.0.

Sure, they might like Ruby more, but when Microsoft releases C# 3.0, functional programming will finally be mainstream in a way that Ruby would take years to reach. And for an advocate of functional programming, that should be an event of astounding importance. But not one single mention of it is made on either site, or many others that advocate LISP, ML, Hakell, OCaml, etc. Will C# 3.0 do everything these languages do? No, but I think it hits the most important points, at least as in the area of functional programming.

Why do these writers completely fail to mention such a momentous turn of events for one of their most dear principles? I can only conclude it is a hatred of Microsoft, which causes them to think irrationally when it comes to anything from Microsoft. If it was just a few writers, this wouldn’t trouble me so much, but it’s not just a few writers. I see so many people who will simply pretend as all Microsoft’s products with less than 90% market share are insignificant.

I expect the reaction will be different when Sun announces that they intend to support functional programming in Java as well. I’m not sure when it will happen but I am sure they are thinking about it. If you look at the specs for the pluggable annotation API closely, it talks “new language features”, and visitor classes. This can only mean one thing, lambda functions with closures. Of course, unless Sun is being very tight lipped about this support, Microsoft will beat them to the punch. It’s unlikely that Sun is hiding anything because the JCP process does not really allow for that.

It’s nice to see that Sun has woken up, and isn’t ignoring what .NET is doing, as they once did. J2SE5 was a litany of copycat features, for which I applaud Sun, rather than deride them. And of course, functional programming in general is a copycat of what LISP did long ago. But that’s ok, because with programming languages it’s not all about which language was first. We programmers are more practical than that.. Aren’t we?

12
Aug
06

IDEs, Dynamic Languages and the Importance of Metadata

I realized something curious today. As programmers, we use the same tools for two very different tasks, reading code and writing code. Our IDE’s (or text editors), display only one view of a program’s source code, and it is universal. But the requirements for reading code and writing code are very different.

When writing code, programmers universally appreciate succinctness. It’s often over emphasized because for most programmers writing code is the fun part, so making it as fun as possible is top priority. But we know eventually, we will expend a great deal more effort and time reading that code. Succinctness has value for readability, but it has limits, which don’t necessarily apply to writing code. It may be easier to type “i”, then “index”, but is it more readable?

So our parameters for reading code are different. When reading code, we should have more information available then we are required to write. Intellisense is a partial example of this vision. Not only does it reduce what you need to type, but insures later when reading, you will have more information available.

Intellisense is not enough however, we should have IDE’s that show us, or allow us to see, implied characteristics that compilers can compute. For example, I really appreciate OCaml’s ability to infer types, signatures and such. When using a prompt, you get to see results of your declarations. But once you go into an IDE, a lot of that information is missing, which is silly because that information is even more important when reading in an editor than writing at a prompt.

I’d like to see that information, and more displayed in my edit/read window without having to hover, click, etc. I’d be ok with a switch to go from read to edit mode if that’s what the interface requires, but I think it’s critical that we stop thinking only about the writing, and begin putting more thought into reading.

One of the things you’ll hear the most from Ruby fans is they like how readable the language is. In many ways, I’d certainly agree, there is a lot other languages can learn from Ruby about readability. But there are some chinks in the armor. I’ve been picking up Ruby lately, and I’ve been frustrated by the lack of support for things I take for granted in Java or C#, such as Intellisense/AutoComplete.

Because it is a dynamic language, which doesn’t really know the type of variables until runtime, tools often don’t know what the author intended when he wrote a set of code. In the long run, this will be a limiting factor for most dynamic languages. One could design a dynamic language with a full type inference system, but that is quite difficult and requires compromises to the dynamic language ethos, so they aren’t. Without this information, IDE tools will be less functional.

But, dynamic languages are all about the language. Everything evolves from the language, and it’s been this way ever since LISP. But today, to make a great development environment you need to look at more than just the language.

First, you should consider your API as well. This was one of Java’s early strengths. It had an excellent well-crafted API designed alongside the language. This was contrary to the C++ development model, which created multitudes of APIs separated from the language, without any strong common base.

As well, you should consider the IDE. This is a recurring strength of C#. The design of C# took into account Visual Studio and the .NET framework and vice versa. C# lends itself to preparsing extremely well, and as a result, features like Intellisense, Refactoring and Class Browsing are highly supported. .NETs assemblies and metadata likewise help support these features extremely well.

I recently read Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, and the most interesting part of the book were the annotated comments. Besides being open about mistakes made in the design of the .NET Framework API, it also makes clear the amount of thought that went into optimizing the API for use with the IDE. By considering features like Intellisense in the design, Microsoft could design the framework to make it easier for developers to find information fast.

It’s amazing how easily and how commonly developers dismiss the IDE from the equation, even when talking about usability. Take this article, “Are programmers people?” as an example. But the IDE is becoming more important with every passing year. Intellisense, Refactoring and Unit Testing are just the tip of the iceberg. Smalltalk was ahead of its time in some of these areas, and coincidentally was the last widely known language with an integrated IDE before .NET.

But automation of these capabilities requires information, and this is the Achilles heel of dynamic languages. By their very nature, they have less information available when the IDE needs it because they don’t intend to figure these things out until runtime. Static types are metadata, and that metadata is incredibly valuable to pre-runtime tools.

I respect dynamic languages. Dynamic languages have done some great things, but most of them are doable in static languages as well. The recent surge in interest in dynamic languages, especially Ruby, has demonstrated the value of features neglected by mainstream language developers for far too long.

Even after this, dynamic languages will have their place and many unique advantages, but I disagree strongly with anyone who thinks static languages are a dying breed. Metadata will become more important in so many ways. What we will be searching for in the future are ways to give our tools more information, with less work. Settling for just providing less information not only cheats tool developers, but also cheats ourselves later on when we want to read our code.

I imagine a day when give us succinct methods for indicating intent, validate that information, and suggest safety while still allowing freedom. In addition to helping write safer code, or allowing secure systems to validate it, I also imagine this data helping us to maintain our code by providing more information and insight to the maintainer than the original author explicitly typed out.

06
Aug
06

Collection of Dynamic Features for Static Languages

Dynamic languages have been gaining support and interest over the last few years. Static languages however still dominate usage, and have benefits, like performance and verifiability, that some dynamic languages would like to replicate. At the same time, some static languages are realizing the value of dynamic languages and are attempting to replicate some of those benefits, while retaining the static capabilities.

I have attempted to create a list of the dynamic features that static languages are picking up on, and how they are addressing them. I am sure this list is not yet complete as most there are a great deal of interesting languages out there these days, and I have not had a chance to review them all. If you know of a few more features or implementations, let me know.

If your interested in static/dynamic crossover, you might be interested in three earlier posts. Inform, Suggest Safety and Allow Freedom, Static/Dynamic? Why not both? and Principles of Language Design – Semantic Capture

Safe Features

Safe features do not require late binding and retain all static type checking ability, while shortening syntactical definition. Sometimes this results in a clearer syntax as well. Safe features stretch from syntactic translations, like type inference, to functional extensions like lambda expressions.

Type Inference

Found in: C# 3.0, Visual Basic 9, F#, Fortress, ML, OCaml, Haskell, Boo, Nemerle, Groovy?, Clean

Type inference is the simulation of dynamic syntax while maintaining static typing. A variables type is not explicit, the compiler infers it from the context. The depth of inference can vary, but usually takes into account at least constructors for local variables.

Note: I could not really tell whether the def statement in Groovy was a dynamic variable or a type inference mechanism.

Structural Subtyping

Found in: Haskell, ML, OCaml

Also know as: ad hoc interfaces

Structural subtyping can be thought of type inference, where the name of the type is not taken into account, but only the structure of the type. The ultimate result is very similar to duck typing, while remaining completely statically typed.


Anonymous types

Found in: C# 3.0, Visual Basic 9, haXe, OCaml

Also know as: immediate objects

Anonymous types allow using dynamic syntax for temporary types or data structures. Under the covers, these are just another type with an implicit name.

Tuples

Found in: OCaml, Nemerle

Tuples are very similar to anonymous types, but tuple members do not have names. Technically I believe the term tuple could be used to refer to anonymous types as well, but in practice where the term tuple was used it was with unnamed members.

Lambda Expressions

Found in: C# 3.0, Nemerle, ML, OCaml, Groovy, Boo, Nice

Generics

Found in: C# 2.0 Visual Basic.NET, Java 5, Managed C++, Nemerle, ML, OCaml, etc.

It is somewhat debatable if generics are a dynamic feature. They fulfill a very specific piece of the self-generating program capability available from many dynamic languages, but do it in a very different way.

Unsafe Features

Unsafe features shift evaluation to runtime through techniques such as reflection, lazy evaluation, or runtime interpretation.

Runtime Casts

Found in: C#, Visual Basic, Java, C++, Nemerle, Boo, etc.

Not commonly considered a dynamic feature, casts that evaluate type coercion to at runtime are a dynamic feature. In statically typed languages, runtime casts usually only result from explicit casting, yet the two terms are not synonymous.

Dynamic variables (a.k.a. Duck Typing)

Found in: Visual Basic.NET, haXe, Nemerle, Boo

A dynamic variable is quite simply a variable that not only can hold an object of any type, but allows any member name or signature to be valid at compile time. Some languages like Visual Basic enable/disable this globally or per file. Other languages have a specific dynamic type.

Dynamic interfaces

Found in: Visual Basic 9, Nice

A dynamic interface allows for after the fact interface definition. A dynamic interface is similar to a dynamic variable, but defines some restrictions. Like a dynamic variable, a dynamic interface at compile time accepts assignment from variables of any type.

Dynamic blocks

Found in: haXe

A dynamic block allows evaluation of a series of statements to either partially or fully at runtime.

Known implementation techniques

Generate reflection code. Miniature interpreter.

Dynamic identifiers

Found in: Visual Basic 9

A dynamic identifier allows evaluation of individual identifiers at runtime. In many ways, dynamic identifiers are reflection short hand, but their syntax is similar to that of dynamic languages.

05
Aug
06

Inform, Suggest Safety and Allow Freedom

I was reading Static Typing Where Possible, Dynamic Typing When Needed, and was reminded of several of my posts (like Static/Dynamic? Why not both? and Principles of Language Design – Semantic Capture). It is amazing to me how precisely this article reflects my philosophy of language design. It is also amazing I did not run across it earlier.

One of the points I enjoyed the most was the [implicit] concept in 2.4. I have been thinking about a similar syntax, but with a different application and a different point of view. Meijer and Drayton focus on generics here and contract, but I was thinking more about a refinement of Visual Basic.NET’s Option Implicit statement.

That option allows for late bound code, mixing up the notion of compile and runtime. Under the covers, it uses reflection to translate

object b=newButton();

object c=b.BuckColor;

to:

object b=newButton();

object c=b.GetType()

.GetField(“BuckColor”)

.GetValue(b);

In my version of things, the option is not per file, but per block. Borrowing from C#’s handling of pointer’s we would use a syntax like:

try unsaferuntime { … }

or:

[implicit]try { … }

The try might be optional, but the compiler would definitely suggest using try and catching exceptions inferred as possible. Obvious exceptions might be MemberAccessException, but possibly there should be a “ReflectionException” that would only catch exceptions resulting from implicit runtime typing.

Any member access within the block that would normally cause a compile time error, the compiler would translate to the equivalent reflection code, shifting evaluation to runtime. This combined with other techniques such as file or project level implicitness offers a migration path from partially dynamic to mostly static.

Developers could start with project level implicitness turned on for rapid prototyping. Later, when it feels appropriate to apply a stricter set of rules, enable explicit compilation, and use implicit try blocks for corner cases. Alternatively, leave implicit development enabled and used the blocks to certify certain sections as “known”, changing or suppressing warnings.

These ideas all tie into a larger philosophy, founded on three tenets. Development tools should allow freedom. Development tools should inform the developer. Development tools should suggest safety.

It is not the development tools right to prevent you from writing bad code. This runtime should be the enforcer, though this could also include the JIT compiler. The runtime often will have cause to enforce a level of safety, but this is system specific. The development complier has no such justification. When a runtime refuses to execute code it cannot verify is protecting a system. When a development compiler refuses to compile unverifiable code, it is presenting an obstacle. It gains no safety for which warnings would not have sufficed.

However, compilers should inform the developer about the possible consequences of their actions. Developers may have a need to insure their code is verifiable. The compiler should be able to classify the safe and unsafe elements so that inspection can focus upon the unverifiable bits. In general, a development tool should provide any information it can present to the user in a concise, manageable, and informative form.

Last, development tools should suggest safety. It should be possible to ignore this suggestion if you wish, but it should be there. This does not require warnings, popups, etc. that cannot be disabled. It requires rational defaults that require the developer to make a rational decision to accept the consequences.

In a sense, this last rule is minor since it may amount to no more than a check box in an options screen, but it is a principle developers should remember when developing for users. As smart as we developers think we are, we are still users and a simple rule like this applies to us just as much as any other user.

P.S. I made one very interesting realization while writing this. Visual Basic 9.0 is not just a copy of the C# 3.0 features, there is actually some unique and interesting stuff there, though it’s way at the bottom of the list, like Dynamic Interfaces (or Strong “Duck Typing”) and Dynamic Identifiers.

07
Jul
06

The JavaScript VM?

There’s an interesting trend going on these days, where many languages are adding features to compile their code into Javascript. For example Ruby, Java, C# are all doing it. Supposedly, the original idea came from a company called Morfik, but I know very little about that.

What I find interesting about this is that JavaScript is essentially being abandoned as a language and converted into an IL. Not having much respect for JavaScript myself, it feels very much like a first class hack, and I wonder how long it will live on. It’s easy to see why it is happening, JavaScript is already everywhere, so why not repurpose it?

But thinking longer term, clearly there must be better alternatives (CLR and JVM) than JavaScript.

30
Jun
06

From Practice to Pattern to Syntax

In the software industry, Design Patterns are widely recognized. It is a widely held assumption that these patterns require customization. Recently, I have been wondering if the philosophy that these elements need customization is correct.

The source of this philosophy is obvious as Christopher Alexander’s book The Timeless Way of Building is a key source of inspiration for the authors. Alexander believes strongly that one factor contributing to the “lifeless character” of modern building is the use of modular components, and the lack of “fit” that results.

While there are many parallels between the process of building beautiful and functional buildings and building software, there are certainly significant differences. As an industry, we have sacrificed potential, mostly in the form of execution cycles, for modular components, higher-level languages, operating systems, etc. The construction industry has also made sacrifices of potential for the cost benefits of modular components. However, in the case of construction, the sacrifice has been of quality, execution time.

For the construction industry there is no equivalent to execution cycles; construction time is a separate concept more akin to development time. Even if there were such a concept, it is unlikely the construction industry would have it in such excess as the software industry. As long as computing power continues to advance, there will be excess capacity to fuel these tradeoffs.

Can design patterns move from the realm of patterns into reusable modules? Better yet, can they move from patterns into reusable syntax? It is already happening, albeit slowly, and with little formal recognition. Recognition is low because the efforts do not completely implement the patterns. Many patterns have complexities that syntax cannot completely capture. Syntax however can get close. How close would it need be for the pattern itself become unnecessary?

I have not spent the time to think about every pattern and how this might happen, but my guess is, yes, it is possible. Similar to the sacrifice of many custom assembler algorithm patterns, for generic looping constructs, I believe the same will happen to today’s patterns. The Iterator looks to be the first casualty, as languages like C# and Ruby build in constructs that codify the pattern into a much easier to use, if slightly more restrictive sheath (yield). Delegates also change a many of the patterns, especially Observer.

This is not totally a new development either, as languages as far back as Smalltalk, implemented language features that made Proxies trivial. In truth, every pattern has a large degree of busy work involved, and the best languages in the future will likely be those that automate these elements. Some creative features might take the place of patterns, or the most common forms of each pattern might become codified in the language syntax.

One idea is better codification of the delegation-by-composition design. This would allow a member variable to proxy for a class’s external interface. The example below shows one possible syntax for this.

public interface IAsset
{
decimal purchasePrice {get;}
}

public class OwnedPlane : Plane, IAsset
{
IAsset interface by asset;
private bool operational;
public bool Operational { get { return isOperational; }}

public void bought(Corporation buyer)
{
asset = new CoporateAsset(buyer);
}

public void bought(Person buyer)
{
buyer = new PersonalAsset(buyer);
}
}

public class PropertyTaxCaluclator
{
public decimal TaxPlane(OwnedPlane plane)
{
return plane.purchasePrice * (plane.operational ? FAATaxRate : normalTaxRate);
}
}

You could have a tool generate code like below, in place of the line in bold, but when then this code must be maintained. Even if your tools can regenerate the code, it will still be a distraction to review. (Remember in a real example you might have dozens of properties.)

private IAsset asset;
public decimal purchasePrice { get { return asset.purchasePrice; } }

If you are not planning to modify the code, you are far better off with a simple concise statement that says exactly what you mean. There likely will be resistance to codification, as it will require some sacrifices. In addition, there is likely to be at least a few bad implementations that do more harm than good. In the end, I believe codification will win out, as it is simply the most succinct, direct, complete and meaningful implementation.

In order to achieve a higher level of abstraction, you must provide your tools with information about a higher level of intent. The only caveat is that the design of systems to capture that intent is hard, and often requires a progressive process that first accumulates knowledge in documentation like Design Patterns. Later, general-purpose implementations incorporate this knowledge to cover the most common cases. Eventually, however, the lessons learned from these preliminary steps should result in language constructs that replace the most common designs.

For very complex patterns, I imagine there will be more intermediary steps, such as implementations in tools like Software Factories. The software factory concept is something I have only recently begun to understand, but it shows a lot of promise as a bridge between knowledge and final implementation. The promise is actually much bigger than that, but that is best left for another day.

The name software factory sounds awfully scary, conjuring up visions of slave driver bosses, and rote development. The name is unfortunate, because this is quite far from the truth, intent and reality of software factories. If I might, I would offer up the alternatives of Framework or Pattern Factories. Not only do these names better represent actual abilities, but they also avoid the negative connotations of “software factory”.

A software factory cannot generate a complete application. A software factory can generate a complexly working framework, and can use further recipes to generate pattern implementations. Only when actual business logic supplements the generated code is an application complete.

12
May
06

Ruby.. BOO! CLR LISP JavaSchools.. and a total lack of focus

I finished the Ruby book I was reading online, but unfortunately, it ended before the continuations, so it looks like I will need to find another resource to finish up. I suppose I could start writing a program, but I would rather keep digging. If anyone has a good recommendation for an advanced Ruby resource (and by advanced I mean high end features, not written in gibberish), send it on.

So instead of following up on Ruby, I instead started looking at Boo. Someone suggested it and I have to admit, I am impressed. I do not care for some of the syntax, but I really like the type inference system, which goes a bit farther than var in C# 3.0. I do however wonder if making inference the default, instead of explicit through var is the right thing to do, but I’m not really sure one way or the other yet.

As far as syntax goes, one thing I do not understand is def. Why is that there? However, ignoring some oddities like this, it is a beautiful achievement. Beyond the language itself, the site is really interesting because of how well it demonstrates the not well know cross platform capabilities of .NET. See.

I knew about Mono before, but I had never heard of GTK# before. Boo has an Eclipse plug-in as well. Oddly, there is no VS.NET plug-in for boo. The whole project is an interesting mash-up of many different technologies that people generally assume do not fit together.

Boo also has some cool language features.

On a related note, I also read a set of articles that I found interesting. Sriram seems to be in the same mode as I am, trying to soak up the juice from languages like LISP. I would totally agree that I have failed to fall in love with LISP, or even Ruby. There are some cool things there, but I am driven away by others. LISP is far worse in this way. Despite that, I am still very happy that I spent the time on it. I may never write a single line of LISP code, but that was not the point was it?

Sriram, pointed to an article on teaching Computer Science. While Joel may be right that his tried and true tests do not work as well on someone who has not studied LISP or something similar, I wonder if he is not making the same mistake he criticizes others for. That is that he is using “grep” to evaluate resumes. He is looking for LISP experience however instead of Java experience. What he should really be looking for is a way to test his candidates that does not rely upon prior knowledge that is unrelated to the job.

Joel compares the ability of developers to grapple with recursion and pointers with the ability to create architecture, because they require a similar skill of breaking down problems to properly solve. However, why not use a test that only requires that skill, but only requires commonplace knowledge. Even better might be to actually test their ability to create architecture, but I suppose Joel feels that either this would take too long, or that he does not expect his candidates to come to the job with that knowledge.

However, if what you are looking for is problem solving skills and architecture knowledge, why look for LISP knowledge, or pointer knowledge, etc. which may never come up for the average developer?

11
May
06

Static/Dynamic? Why not both?

So.. it’s been quiet here. I decided, a bit more than a week ago to learn LISP. I have been hearing things about LISP every so often, how great it was, so I got this feeling that I should give it a look. Somehow, in the middle of this project I decided to study Ruby as well. To add to all this I’m trying to compare both of them to C# 3.0.

It’s been an interesting journey (which is not done yet). Both languages are of the dynamic variety, which I have a personal bent against. I see the value of dynamic typing for some situations, and it certainly made a number of interesting features of both languages easier.

For example, dynamic typing is very useful for interpreters (like IRB or REPL), and it is easier to include metaprogramming, or LISP style macro capabilities in a dynamic language.

On the other hand, static typing has immense benefits too. The obvious one is the ability of the compiler to protect you from yourself. Most dynamic typing advocates tend to dismiss this as the argument of a “newbie”, but the truth is that it is not as simple even as protecting you from yourself, but perhaps protecting you from your neighbor, etc.

It is naive to assume that experienced developers don’t make mistakes. In fact, the most experienced developers probably make more mistakes than average because unless they are lazy they are working on harder problems.

But.. I am starting to rehash a common debate, which is totally unnecessary. It is unnecessary because I don’t believe that dynamic and static typing are wholly incompatible. Maybe if the two camps would bury the hatchet we’d see better alternatives.

Dynamic languages for example, can easily include psuedo-static typing, and quite a few do to a very limited degree. But why is it so limited? Take LISP as an example. LISP includes support for declaration of types, but it is very rarely used, except for performance gains. I could be wrong here, but I think the main reason is LISP implementations never included type checking. Most dynamic languages actually tend to eschew the concept of compilation entirely.

I think it is great to be able to quickly test your code in an interpreter (or JIT as is the general case), but why aren’t there systems to check your code when preparing a release? Actually, preparing a release is too late. Really, it should be like Visual Studio, where it is checking your code as you write it, but I see how this might be a bit difficult, so I would settle for having basic code validation tools.

However, good validation tools require support from within the language, and from the developers. It is obvious that with runtime metaprogramming you can break things a validation tool would think was ok, or vice versa, so languages would need a way for you to suppress validation on specific sections, or the false positives could be a big problem.

On the static side, I actually see the trend developing already. C# 3.0 (and C# 2.0) are excellent examples of how static languages are working to bring features traditionally associated with dynamic languages to the static world. C# 3.0 also introduces some pseudo-dynamic capabilities. “var” is an example of this. Technically everything is still static, but it does not always feel that way, and when combined with anonymous types, methods, and lambdas it does more than just feel different.

There is still plenty left to do here though. I think it might be very interesting to introduce an almost totally dynamic option to C#. I was thinking of the ability to take a try/catch block and append mode options to the try. For example:

try runtime
{

x.IHopeThisMethodExists();
}
catch (RuntimeCompileException e)

Of course code like above would be treated with about the same level of regard as unsafe {} but it could be very useful for testing some changes quickly, or for building mini-languages into applications.

Duck typing is another option, approachable from either side. Dynamic languages can do some duck-type code validation, and static languages can use it as well with the proper restrictions. I static language should have little difficulty in generating “anonymous” interfaces at compile time if that is how the developer designs things. You could just as well reuse the try runtime metaphor as try ducktime… or maybe something a little less silly.

Anyhow, that is about my limit for the night.




Pages

Top Clicks

  • None

a


Follow

Get every new post delivered to your Inbox.