Understanding Anonymous Methods
It appears that the next version of Delphi will support a feature called anonymous methods. The circumstances in which one might use an anonymous method do not seem to be obvious to everyone in the Delphi community, so I’m going to attempt to answer that.
There is, at the moment, no shipping version of Delphi which includes anonymous methods, so I’m basing my discussion on my experiences using them in other environments. The final, released version may include a different feature set and what I describe below.
First, let’s answer the obvious question, with the obvious answer: What can I do with an anonymous method which I can’t do without an anonymous method? Nothing. In fact, there’s nothing which you can do with Delphi which you cannot do with ASM. Anonymous methods are a convenience suited to certain styles of programming, like strong, static typing, and object orientation. They will probably seem useless to people who do not adopt those styles of programming, just as virtual methods will seem useless or dangerous to a non-OO programmer.
I suspect that most "Pascal programmers" view procedures as being a fundamentally different type than other data structures. In the static typing the world, we typically define the shape of a data structure at compile time, and the contents at runtime. By contrast, even when passing a procedure as an argument to another procedure, in older versions of Delphi we have had to define both the shape and the contents of the procedure at compile time. Only the arguments can be set at runtime.
With one exception: Nested procedures. Let’s talk about that, for a moment.
Nested procedures, scope, and variable capture
Nested procedures are procedures declared inside of another procedure. This essentially reduces the scope of the nested procedure to being callable within the nesting procedure only: Here is a simple example.
procedure MyClass.Foo;
var
i: integer;
procedure Bar;
begin
Inc(i);
end;
begin
i := 1;
Bar;
WriteLn(IntToStr(i));
Bar;
WriteLn(IntToStr(i));
end;
procedure MyClass.Other;
begin
Bar; // compiler error
end;
The output of calling Foo will be the following lines, written to the console:
2 3
There are two things to note here. First, note that Bar can "see" the variable i, which is declared as a member of Foo. Outside of the Delphi community, this feature is often called variable capture, although for some reason that term doesn’t seem to be common within the Delphi community. But that’s what it is. Second, note that the scope of Bar is limited to the Foo procedure. That’s nice, from a modularity point of view, but it’s absolutely critical when combined with variable capture. Outside of the scope of Foo, the variable i has no context/value.
Even the inside of the Foo procedure, however, you cannot assign Bar to an event property or any other procedure reference. The way that variable capture is handled internally makes this impossible, without some hacking.
Now, one might reasonably ask what the value of that variable capture feature is. After all, in the example above, I could just as easily have passed i to Bar as a var argument, and the result would have been the same, albeit at the expense of a bit more typing. Indeed, in the case of nested procs, variable capture is really little more than a labor saving device.
Anonymous methods
Returning to anonymous methods, let’s start with the definition. An anonymous method, as the phrase implies, is a method without a name. In addition to being nameless, anonymous methods, in most environments, include some form of variable capture.
According to the Delphi roadmap, anonymous methods will be assignable to procedure references. You can see an example of this on Andreano Lanusse’s blog.
The combination of assignability and variable capture is quite powerful, because it effectively means that I can change the signature of the procedure reference type in the definition of the anonymous method. That is, I can pass values which are not included in the arguments declared in the procedure reference declaration. That’s unnecessary and perhaps even confusing if I’ve written the "reference to procedure" declaration myself. In this case, I should just include the necessary arguments. If, however, the declaration was written by someone else — say, the author of a framework — it’s incredibly convenient, as I can now pass values which the framework author hasn’t included on my behalf.
In the past, I’ve had to use some fairly ugly kludges to get around this limitation, such as declaring a new class field to hold some value which I only wanted to use inside of an event handler whose signature I did not control. With variable capture, these kludges are unnecessary.
This returns us to the issue of "programming worldview" to which I alluded at the beginning of this post. To a programmer unaccustomed to thinking of functions as values, with functions living in one little container, and data structures living in another little container, this may all seem a bit odd. But if you consider a function as a bit of data, defining both behaviors and passed values, it’s not so strange. Of course we can define data at runtime, just like we’ve always done.
Share This | Email this page to a friend
Posted by Craig Stuntz on August 4th, 2008 under Delphi | 7 Comments »Alternate View Folders in ASP.NET MVC
Stephen Walther recently posted a tip on how to load an ASP.NET MVC View from a folder other than Views\{controller}\ or Shared. He notes that it’s possible to hardcode the path to a View in your Controller action. He also states that you should not do this:
Now, I want to be the first to warn you that you should never, never, never use this tip (Please delete this entry from your news aggregator immediately). There is a good reason for following the conventions inherent in an MVC application. Placing your files in known locations makes it easier for everyone to understand your application.
Now, if the only types of Views that you have an application are views which directly correspond to a single controller or widely shared items like master pages, he’s right. With more complicated architectures, you may need other choices, and the MVC framework has an extensibility point built-in for this. To the extent that Stephen’s point was that it’s never appropriate to hardcode a path inside a controller, however, I completely agree with that. But there may be legitimate reasons to probe other paths, and it’s also interesting to look at why the framework looks in these specific places in the first place.
I have, I think, a fairly good reason for wanting the MVC framework to probe other folders when looking for a View. I’ll explain that at the bottom of the post, but first, here’s the technique. I want to thank Jens Hofmann for pointing this out. His needs are slightly different than mine — he wants the framework to always probe different folders, rather than adding one more folder to the list of folders probed — but his post (in German) pointed me in the right direction to solve the problem. In contrast to Jens’s tip, I’m going to subclass the default controller and extend its list of paths, rather than replacing it altogether.
The ASP.NET MVC framework uses a class called a ViewLocator to find view files. The default ViewLocator is a subclass called WebFormViewLocator. This by itself suggests one reason why you might want to replace the ViewLocator; if you’re developing an alternate markup language, your views will probably have different template file extensions than a WebForm view, so an alternate ViewLocator will be needed.
What I did was to subclass WebFormViewLocator and add my custom path to the list of paths probed, like this:
public class EntityViewLocator : WebFormViewLocator {public EntityViewLocator() { ViewLocationFormats = ViewLocationFormats.Union(EntityViewFormats).ToArray(); }private static string[] EntityViewFormats = new[] { "~/Views/Entities/{0}.aspx", "~/Views/Entities/{0}.ascx" }; }
The class is public for unit testing convenience. Update: Cleaned up code 1 August 2008.
Now you need to assign the ViewLocator to the Controller. One way to do this is in the Controller itself. But I already had a ControllerFactory, so I did it there.
So why do I bother with this? Why not just use the standard folders?
In one of the applications I’m developing now, the great majority of Controllers and Views are dynamically generated to correspond to a type from an Entity Framework model. I have a very large number of "controllers," but most of them don’t actually exist as types or source files. Instead, a single, generic controller can "pretend" to be a specific controller for a specific entity type. Most entity types share completely dynamic views, with no special knowledge of specific controller/entity types, but a few have entirely custom views, which are tightly bound to certain controllers. Structurally, it makes sense to group these "entity views," as well as their field templates, together, rather than dumping them in with master pages, or creating a folder to correspond to a "controller name" which doesn’t actually exist, since a single controller is used for most entity types.
Share This | Email this page to a friend
Posted by Craig Stuntz on July 31st, 2008 under Web, .NET | Comment now »InterBase 2009 Partner DVD
I am once again organizing vendor participation for the InterBase Partner DVD. If your company produces a tool, application, component set, etc. which explicitly supports InterBase, the Partner DVD is one of the best ways to ensure that your software is available to anyone who purchases InterBase. You can include a full version, a trial, or just information about your product; whatever is appropriate for your needs.
As always, participation in the Partner DVD program is free. The only real requirement is that your software has to explicitly support InterBase. If you would like to have your product on the Partner DVD and are not already participating, please send an e-mail to craig underscore stuntz at acm org
Share This | Email this page to a friend
Posted by Craig Stuntz on July 23rd, 2008 under InterBase | Comment now »The ADO.NET Entity Framework vs. NHibernate and Other ORMs
In the past couple of weeks, I’ve had occasion to look fairly closely at the ADO.NET Entity Framework, and compare it to NHibernate. Of course, before I even started, I went out and read what other people had to say on the subject. Many people point to this post by Danny Simmons as approximating the "official" Microsoft position on the subject, and commenters around the web seem to focus specifically on what Danny calls "a [not yet delivered, but] much larger vision of an entity-aware data platform." That’s interesting, but there are differences which exist today which are perhaps even more interesting. As Danny points out, "The EF was specifically structured to separate the process of mapping queries/shaping results from building objects and tracking changes. "
The Entity Framework goes to fairly extreme measures to ensure that the bidirectional mappings between the store (database, usually) and the client entity model are correct, provably, when possible. You can read about that in great detail in this paper, but one very visible implication of it to the developer is that in the Entity Framework, you supply separate metadata descriptions for the store and the object model, plus a third description to bridge the two. Contrast that with a Hibernate mapping, which rolls all three together into one description. Erik Meijer and José Blakely elaborate on this point in an interview with ACM Queue’s Terry Coatta:
TC: You mentioned object-relational mappers. A certain portion of our audience has worked with products such as Hibernate or NHibernate and other commercial ORM systems. One of the existing characteristics of LINQ and the Entity Framework is that they divide traditional ORM into two pieces: one part handling mapping and one part handling querying. Is that a correct view and why is this separation reasonable?
JB: Several OR mappers bundle these two concerns together, and that actually makes sense when the only problem you’re trying to solve is how to bridge the gap between the application and the database.
But we should also look at another very broad class of mapping scenarios. We are building database management systems and data services around SQL Server— data services such as replication, reporting services, and OLAP. These all provide services at higher semantic levels of abstraction than does the relational model.
[…]
Thus, when we look at the impedance mismatch both of applications and data services, we realized that for the data-services case, you don’t want objects with methods and behaviors. What you want is a value-based, richer structural data model.
By value-based, I mean the ability to have a high-level constructs such as entities and relationships but without the behaviors. Just as the relational model is a value-based model, we felt that we needed to provide a layer of abstraction that is richer in terms of entities and relationships. Therefore, the Entity Data Model and the Entity Framework became a natural layer of abstraction that we felt had to be built, and it’s at that level of abstraction where the mapping between richer-level entities and semantic concepts such as inheritance is abstracted.
Now the Entity Data Model, which is the formalism that defines the Entity Framework value-based layer, is very close to the object data model of .NET, modulo the behaviors. We decided to let the Entity Framework take care of all the mapping concerns and then just build than programming-language veneers, or wrappers, over entities to expose a variety of programming-language bindings over this infrastructure.
EM: I would like to point out that there’s a deep analogy with how I explained LINQ in the beginning. We are trying to extract not one particular case where you go from tables to objects, but rather a wide variety of different things for different uses. So instead of having a one-often thing, we are trying to generalize this concept so that there are many other situations in which is applicable.
Ironically, one of the places where this distinction is most visible is when attempting to use the Entity Framework designer in the current .NET 3.5 / Visual Studio 2008 Service Pack 1 Beta. I say "attempting" because, at this point, if you do any serious work with the Entity Framework, you’re almost certain to be editing the EDMX file (which is XML) by hand. It’s very easy, at the moment, to make the designer create EDMX which is either not a valid or not parsable by the designer. Part of this is, no doubt, because the Entity Framework is quite a bit more mature than its designer. The Entity Framework has its roots in WinFS and Microsoft Research, while the Visual Studio designer appears to be a more recent addition to "productize" the Entity Framework. Presumably, the more glaring bugs in the designer will be fixed before release.
But part of me wonders if the instability in the designer is due not only to its relative immaturity, but also to the fact that it tries to present a single face for a mapping which is fundamentally a three-part system. Indeed, there seems to have been a drive from the "Entity Framework tools team" to roll these three parts into one. The designer shows (graphically) you only the conceptual model, for the most part. Some parts of the storage model filter through here and there, and the mapping can be seen when you click on an individual element. The paper I referenced earlier shows you the three parts in a graphical form, but the Entity Framework designer shows you only a piece of this, mostly the OO side of things.
One of the mental barriers that you have to get over when designing a good object relational mapping is the tendency to think primarily in object oriented terms, or relational terms, whichever suits your personality. A good object relational mapping, though, incorporates both a good object model and a good relational model. For example, let’s say you have a database with a table for People, and related tables for Employees and Customers. A single person might have a record in all three tables. Now, from a strictly relational point of view, you could construct a database VIEW for employees and another one for customers, both of which incorporate information from the People table. When using a one VIEW or the other, you can temporarily think of an individual person as "just" an Employee or "just" a Customer, even though you know that they are both. So someone coming from this worldview might be tempted to do an OO mapping where Employee and Customer are both (direct) subclasses of Person. But this doesn’t work with the data we have; since a single person has both employee and customer records (and since no Person instance can be of the concrete subtype Employee and Customer simultaneously), the OO relationship between Person and Employee needs to be composition rather than inheritance, and similarly for Person and Customer.
So would be Entity Framework designer be better if it graphically showed you all three facets of your mapping? It’s hard to say. Our model appears complicated enough in just the OO view, even though it represents less than 100 database tables, which is significantly smaller than the schema for our production applications. Attempting to add the storage metadata and the mapping to that diagram would be putting more lines on a drawing which already threatens to make the term "spaghetti code" literal.
At the same time, though, certain operations really beg for an explicit representation of the storage metadata, the OO model, and the mapping between them, especially when configuring relationships and inheritance. The latter, in particular, we have found difficult to do in the visual designer without corrupting the EDMX.
Perhaps more importantly, though, it may be true that the "simplification" of the designer is part of the reason that people have to ask what the differences between the Entity Framework and NHibernate in the first place. If you just look at the XML files for both systems, the difference stands out a lot more.
Share This | Email this page to a friend
Posted by Craig Stuntz on July 17th, 2008 under .NET, ACM | 1 Comment »Moq and MvcMockHelpers
I’m working on some unit tests for an ASP.NET MVC application I’m developing. One of the tests ensures that if I construct a URL using Html.ActionLink that the URL which is returned, when fed into the routing system, becomes a correct representation of the route data used to build the URL originally. I’ll discuss this further in a future post, but today I’m going to talk about Moq. Unfortunately, this type of testing requires more mocking than you’d really prefer, despite the significant improvements in unit-testability in recent previews of the ASP.NET MVC framework.
I started with the MvcMockHelpers library released by Scott Haselman. It does quite a bit of what I need, so that saved me a lot of work. Scott’s library supports three different mocking frameworks; of these, I chose Moq.
My tests hit some areas of the HttpContext which Scott’s mock didn’t implement, so I set out to extend it. One bit, HttpContextBase.ApplyAppPathModifier, was a bit more challenging to mock, despite the fact that the result I needed was quite simple: The mocked function should simply return its only argument. The Moq demos don’t cover this case, although it is a supported feature in the 2.0 version. After a little digging around through the forums and the change logs, I figured out how to do it:
response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>())) .Returns((string virtualPath) => virtualPath);
There are two parts to this. First, you specify that this mock will match a call to ApplyAppPathModifier with any string argument. That is the It.IsAny bit. Inside the Returns call is a lambda expression which specifies how to turn a string argument into a result. In this case, the expression is very simple.
So, for anyone who wants it, here is my current implementation of the FakeHttpContext() method. It returns a mocked HttpContext which is good enough for the unit testing I’m doing at the moment.
public static HttpContextBase FakeHttpContext() { var context = new Mock<HttpContextBase>(); var request = new Mock<HttpRequestBase>(); var response = new Mock<HttpResponseBase>(); var session = new Mock<HttpSessionStateBase>(); var server = new Mock<HttpServerUtilityBase>(); var user = new Mock<IPrincipal>(); var identity = new Mock<IIdentity>(); request.Expect(req => req.ApplicationPath).Returns("~/"); request.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/"); request.Expect(req => req.PathInfo).Returns(string.Empty); response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>())) .Returns((string virtualPath) => virtualPath); user.Expect(usr => usr.Identity).Returns(identity.Object); identity.ExpectGet(ident => ident.IsAuthenticated).Returns(true); context.Expect(ctx => ctx.Request).Returns(request.Object); context.Expect(ctx => ctx.Response).Returns(response.Object); context.Expect(ctx => ctx.Session).Returns(session.Object); context.Expect(ctx => ctx.Server).Returns(server.Object); context.Expect(ctx => ctx.User).Returns(user.Object); return context.Object; }
Share This | Email this page to a friend
Posted by Craig Stuntz on July 10th, 2008 under Web, C# | 1 Comment »JAWS, XP Themes, and Accessibility
It seems that the popular screen reader (software which translates text on the computer screen into spoken audio for the blind) JAWS has problems with applications produced in Delphi when they are manifested for Windows XP. I don’t know if the problem is limited only to Delphi applications, though. What I do know is that we tested the latest version of JAWS with a do-nothing application which simply displays a single, standard, text edit control, and a standard label which specifies the text editor as its FocusControl. When we produce the application without an XP manifest, JAWS reads the caption correctly when the editor is focused. When we add an XP manifest, JAWS no longer reads the caption.
So if accessibility for the blind is important for your software, it would probably be a good idea to download the free demo version of JAWS and test your software. If it doesn’t work, try making the manifest optional.
One would think that the makers of JAWS would want software producers to test their products with JAWS. But according to a salesperson for Freedom Scientific, there is no developer program for the tool. JAWS is moderately expensive — about $900 — but this is not a barrier for us. What we would really like is to have access to a defect reporting system for JAWS and early access to future versions of the software.
Update: Darrell Shandrow, from the Blind Access Journal, comments on this post.
Share This | Email this page to a friend
Posted by Craig Stuntz on July 3rd, 2008 under General Software Development, Delphi | 2 Comments »Visual Studio 2008 Service Pack 1 Beta Installation Fails
The other day I tried to install the Visual Studio 2008 Service Pack 1 beta. The installer failed.
In the installation log, I found:
Patch (C:\DOCUME~1\CMS~1.VER\LOCALS~1\Temp\Microsoft Visual Studio 2008 SP1 (Beta)\VS90sp1-KB945140-X86-ENU.msp;C:\DOCUME~1\CMS~1.VER\LOCALS~1\Temp\Microsoft Visual Studio 2008 SP1 (Beta)\VC90sp1-KB947888-x86-enu.msp) install failed on product (Microsoft Visual Studio 2008 Professional Edition - ENU). Msi Log: <Microsoft Visual Studio 2008 SP1 (Beta)_20080521_093532362-MSP0.txt>
Opening the linked file, I saw this:
DEBUG: Error 2746: Transform RTM.1 invalid for package C:\WINDOWS\Installer\5d5916dc.msi. Expected product {80C06CCD-7D07-3DB6-86CD-B57B3F0614D8}, found product {D7DAD1E4-45F4-3B2B-899A-EA728167EC4F}.
DEBUG: Error 2746: Transform RTM.2 invalid for package C:\WINDOWS\Installer\5d5916dc.msi. Expected product {91C325A6-D5DE-3444-B598-97DF50EE0FAF}, found product {D7DAD1E4-45F4-3B2B-899A-EA728167EC4F}.
DEBUG: Error 2746: Transform RTM.3 invalid for package C:\WINDOWS\Installer\5d5916dc.msi. Expected product {4298C783-524F-3C3E-9B11-36FA64604B2B}, found product {D7DAD1E4-45F4-3B2B-899A-EA728167EC4F}.
DEBUG: Error 2746: Transform RTM.4 invalid for package C:\WINDOWS\Installer\5d5916dc.msi. Expected product {8F10429A-DFF5-3B55-9306-0ADEB337CFD3}, found product {D7DAD1E4-45F4-3B2B-899A-EA728167EC4F}.
DEBUG: Error 2746: Transform RTM.5 invalid for package C:\WINDOWS\Installer\5d5916dc.msi. Expected product {23D0117E-F9A5-364E-A379-70EC2DE02B9F}, found product {D7DAD1E4-45F4-3B2B-899A-EA728167EC4F}.
DEBUG: Error 2746: Transform RTM.6 invalid for package C:\WINDOWS\Installer\5d5916dc.msi. Expected product {F434F50E-7614-3EA8-9008-2FB866B697DA}, found product {D7DAD1E4-45F4-3B2B-899A-EA728167EC4F}.
DEBUG: Error 2746: Transform RTM.7 invalid for package C:\WINDOWS\Installer\5d5916dc.msi. Expected product {BA0C9AAF-1327-3F06-B49C-349B4BE8F740}, found product {D7DAD1E4-45F4-3B2B-899A-EA728167EC4F}.
A commenter on Scott Guthrie’s blog, however, gave me a clue which eventually allowed me to figure out a fix. The installer for the beta cannot deal with hotfixes which have been applied to Visual Studio. Before running the installer, you need to perform the following steps:
- Control Panel, Add or Remove Programs
- Check "Show Updates"
- Scroll to Microsoft Visual Studio 2008
- If there are any hotfixes under this entry, click the Remove button for each
Now the installer should work. The Service Pack installer will add the hotfixes back for you.
Share This | Email this page to a friend
Posted by Craig Stuntz on May 23rd, 2008 under Web, .NET, C# | 2 Comments »Embedded User Authentication Error in InterBase 2007
Yesterday, an InterBase user reported the following error which he received when he tried to add Embedded User Authentication to an existing database in InterBase 2007:
In Delphi code, I log in as SYSDBA and open an existing database. I execute the SQL:
ALTER DATABASE ADD ADMIN OPTIONThe following exception occurs:
ClassName: "EIBInterBaseError"
Error Message:
"unsuccessful metadata update
STORE RDB$USERS failed"
This ring a bell with me, so I asked him to confirm that the ODS (On-Disk Structure; essentially, the version number of the database file format) of his database indicated that it actually was an InterBase 2007 database. InterBase 2007 does not automatically upgrade older databases to the newest file format; you have to backup and restore the database to accomplish this.
He responded:
The database had been automatically upgraded from InterBase 7, and reported
via the TIBDatabaseInfo properties that the On Disk Structure (ODS) Version
was 11.2′.I backed up and restored the database and the ODS Version was then reported
as 12.0.With this version of the database, the exception did not occur.
This tells me that ALTER DATABASE ADD ADMIN OPTION does not work unless the ODS is the latest version available for the current server version. I wish the error message was better, but at least the problem is easy to fix.
Share This | Email this page to a friend
Posted by Craig Stuntz on May 20th, 2008 under InterBase | Comment now »InterBase Procedure Dependency-Checking Bug
InterBase seems to have a bug in checking dependencies when you alter the arguments to a procedure which is referenced by a trigger. It’s easy to work around, though.
Yesterday, and InterBase user reported on the IB newsgroups that he had tried the following steps:
- Alter a procedure to change the number of arguments it takes.
- Alter a trigger which calls that procedure, so that the trigger source passes the new member of the procedure arguments.
Now, if the dependency checking had been working, step 1 would have been impossible, due to the reference to the procedure within the trigger body. The correct way of doing this process is to first ALTER the trigger source so that it does not reference the procedure, then change the procedure, then change the trigger source to reference the new procedure signature. But step 1 did work for this user, and when he tried to step 2, he then received the dependency error. The reason he received the error in step 2 is that InterBase was checking the dependencies of the old (compiled) version of the trigger before it compiled the new version. That doesn’t seem right; if we’re replacing the source code of a trigger, why do we care if the old version is legitimate? So there seemed to be at least two bugs here.
If you find yourself in this situation, probably the easiest way to work around the problem is to ALTER the procedure back to its original form, and then update the trigger and procedure in the correct order.
Share This | Email this page to a friend
Posted by Craig Stuntz on May 20th, 2008 under InterBase | Comment now »"Let It Crash" Programming
This past weekend I read Joe Armstrong’s paper on the history of Erlang. Now, HOPL papers in general are like candy for me, and this one did not disappoint. There’s more in this paper that I can cover in one post, so today I’m going to concentrate on one particular feature of Erlang highlighted by Armstrong.
Although Erlang is designed to encourage/facilitate a massively parallel programming style, its error handling may be even more noteworthy. Like everything else in Erlang, its error handling is designed to be distributed, and for good reason:
Error handling in Erlang is very different from error handling in conventional programming languages. The key observation here is to note that the error-handling mechanisms were designed for building fault-tolerant systems, and not merely for protecting from program exceptions. You cannot build a fault-tolerant system if you only have one computer. The minimal configuration for a fault tolerant system has two computers. These must be configured so that both observe each other. If one of the computers crashes, then the other computer must take over whatever the first computer was doing.
This means that the model for error handling is based on the idea of two computers that observe each other.
Erlang is famous for its features which help programmers to produce stable systems in the real world. Its shared nothing architecture and ability to hot-swap code are well-known. But these features are available in other systems. The "links" feature, on the other hand, seems to be unique. When you create a process in Erlang, you can link it to another process; this link essentially means, "If that process crashes, I’d like to crash, also; and if I crash, that process should die, too." Here is Armstrong’s description:
Links in Erlang are provided to control error propagation paths for errors between processes. An Erlang process will die if it evaluates illegal code, so, for example, if a process tries to divide by zero it will die. The basic model of error handling is to assume that some other process in the system will observe the death of the process and take appropriate corrective actions. But which process in the system should do this? If there are several thousand processes in the system then how do we know which process to inform when an error occurs? The answer is the linked process. If some process A evaluates the primitive link(B) then it becomes linked to A . If A dies then B is informed. If B dies then A is informed.
Using links, we can create sets of processes that are linked together. If these are normal processes, they will die immediately if they are linked to a process that dies with an error. The idea here is to create sets of processes such that if any process in the set dies, then they will all die. This mechanism provides the invariant that either all the processes in the set are alive or none of them are. This is very useful for programming error-recovery strategies in complex situations. As far as I know, no other programming language has anything remotely like this.
In addition to simply killing the linked process, the link can also function as a kind of signal to a system process that a group of processes have died, so that appropriate action can be taken, such as restarting a process group.
Like Armstrong, I cannot think of another system that works quite this way. The closest analogy I can think of is a distributed transaction. But distributed transactions have quite a bit more overhead, because they’re all about providing serializable access to shared data, which Erlang just doesn’t allow.
Armstrong says that the idea of links was inspired by the ‘C wire’ in early telephone exchanges:
The C wire went back to the exchange and through all the electromechanical relays involved in setting up a call. If anything went wrong, or if either partner terminated the call, then the C wire was grounded. Grounding the C wire caused a knock-on effect in the exchange that freed all resources connected to the C line.
Armstrong says that the links feature encourages a worker/supervisor style of programming which is "not possible in a single threaded language."
Share This | Email this page to a friend
Posted by Craig Stuntz on May 19th, 2008 under Erlang, General Software Development | 2 Comments »Server Response from: dnrh1.codegear.com

RSS Feed