|
|
|
|
 Monday, October 13, 2008
mod_managed is now in the FreeSWITCH tree. This replaces mod_mono, and allows selection of either the Microsoft CLR or Mono 2.0+ as the runtime engine to use. All the interfaces, and most of the code, are identical for both versions. Modules written on Mono will work on the CLR version and vice versa.
Check it out.
|
|
Code | FreeSWITCH
|
Monday, October 13, 2008 10:43:10 PM UTC
|
Trackback
|
 Friday, October 10, 2008
In this image, we see Banco Industrial (Guatemala) online bank. The Flash applet displays:
System Hours - Monday to Sunday: From 6:00am to 22:00 hours. Last day of month: From 6am to 21:30 hours
WTF? Closing the online bank? By the way, who writes "Monday to Sunday?" And a 30 minute difference on the last day of the month? The levels of incompetence here just stack up, but it's par for the country.
|
|
Guatemala
|
Friday, October 10, 2008 3:13:41 AM UTC
|
Trackback
|
Every now and then I read an article on VoIP security. These articles almost always go over the obvious stuff such as lack of encryption, eavesdropping and ensuring you firewall your networks and so on. While certainly major issues, especially for a corporate deployment, there are still some other interesting issues.
One thing that keeps getting mentioned is the possibility for VoIP peering. Peering allows VoIP providers to send calls directly to each other (possibly over the Internet, maybe over [semi-]private connections). The main idea is cost savings, since the call doesn't need to go out over the public telephone network (PSTN).
To accomplish this, they'll set up a shared database mapping telephone numbers to VoIP providers. So, when a VoIP provider attempts to place a call, it'll consult this directory first. If it finds the number in there, it'll send it direct to the provider instead of over the PSTN. All the providers sign some sort of contract to say they'll be careful with the database and not populate it with invalid entries. Let's just assume the VoIP provider is trustworthy and hires trustworthy people (this is a stupid assumption, but I've had a peering company tell me this, as the security problems are too obvious without this assumption).
This system actually holds true inside of a VoIP provider's own network. A provider will want to terminate directly to a customer instead of out via the PSTN then back into their own network. So they'll probably have a directory of their own numbers so they can route those directly.
Well first off, now every peering member's security is bound by the security of every other member. If just one "trustworthy" peering provider gets compromised (not a hard task - more on that later), they can pollute the shared directory and hijack phone numbers. Being able to redirect a financial institution's phone number sounds like a profitable attack. An attacker can simply route the call to their system, then pass it through to the PSTN to avoid detection by users. Note that none of the security technologies available can prevent problems with a subverted, trusted, directory.
But it gets easier... Many providers let you port your existing number to them when you sign up. From my limited experience, I've seen some of them immediately activate the number for you, so you can get started and going with their network while the port happens. A port can take a bit of time (and for now, let's assume the porting system is secure), so this sounds like a reasonable approach.
Wrong. First off, the new customer's number will probably go right into the provider's internal database, so all calls from that provider will go to the customer attacker. Depending on the size of the provider, this could be a pretty decent attack in and of itself.
But now, suppose the peering contract didn't specify not provisioning ports-in-progress, or if it did, the implementation people messed up. Now ALL the VoIP providers have been compromised, by a single provider who was agressive in their porting tactics.
Eventually it'll probably get resolved, but even a few hours or days of compromising a valuable phone number can be a significant attack.
What's the threat? As a consumer, in general, I'd not worry too much about people trying to tap my line, just like I rarely worry about the safety of my wired Internet connection. But similar to intercepting credit card info versus hacking a company's database, this is a much juicier target. An attacker who pulls this off gets access to bulk information. Thus, I think the threat of something like this happening is much higher than having my individual calls monitored.
|
|
Security | VoIP
|
Friday, October 10, 2008 12:25:14 AM UTC
|
Trackback
|
 Wednesday, September 24, 2008
One common issue with IEnumerables is that you can't find out anything about them until you use them. A frequent scenario is wanting to know if the IEnumerable is empty before you go ahead and use it. For example, you may want to write a result set to a file, but only if there's actually data.
As far as I know, the .NET Framework has no built-in classes to facilitate this, so I hacked up my own. You use it by wrapping an IEnumerable inside an EmptyCheckEnumerable. Then, when you check the IsEmpty property, it gets the enumerator and calls MoveNext once. When you then go to consume it, it intercepts the MoveNext call and simply returns the previous value. From then on, it just passes through. The result is that you don't consume the IE twice, which can be necesary for performance or other reasons.
Example:
var res = new EmptyCheckEnumerable<object>(dc.Execute<object>("SELECT * FROM foo"));
if (!res.IsEmpty) {
// allocate resources and consume the IE - will only execute the SELECT once
}I suggest creating a "ToEmptyCheck" extension method to flow type information. Code: EmptyCheckEnumerable.cs.txt (2.14 KB)
|
|
Code
|
Wednesday, September 24, 2008 10:11:30 PM UTC
|
Trackback
|
 Friday, September 19, 2008
In a previous comment, someone mentioned the OO mindset ("mold" -- quite appropriate). I don't want to go into it much, but simply "quote for win" something from here http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html. It's a nice take on things and I got a kick out of it:
" The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."
Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
"
|
|
Code | FSharp | Humour
|
Friday, September 19, 2008 6:00:50 PM UTC
|
Trackback
|
 Thursday, September 18, 2008
FreeSWITCH's mod_mono plugin should now work fine on Linux. Additionally, it's in the Visual Studio Solution file, all you need to do is compile mod_mono (it won't build by default). There's also now support for running mod_mono inside FreeSWITCH inside another managed application, just in case you're embedding FreeSWITCH.
For more info: http://wiki.freeswitch.org/wiki/Mod_mono
|
|
FreeSWITCH
|
Thursday, September 18, 2008 2:24:38 AM UTC
|
Trackback
|
I hacked up a little class to enable us to use SQL 2008's Change Tracking feature with LINQ-to-SQL. Change Tracking allows you to see which keys (and optionally columns) have changed in the database from a specific version. The SQL docs have a great overview with lots of examples and information.
Basically, we get a special CHANGETABLE function to SELECT from, which gives us the change information and keys. Additionally, there is the issue of versioning. Changes are only kept so long, so we want to make sure the last version we sync'd is still compatible, otherwise we have to re-initialize.
Finally, in order for our change SELECTs to be coherent, we need to snapshot the database. The easiest way to get this is by turning on Snapshot Isolation. Snapshot isolation allows us to read a virtual snapshot of the database. Any changes made from when we begin our transactions are not visible to us and we do not lock anything we read.
Here's an excerpt from a class I have to provide change tracking for our database:
public DbDataChangeProvider(long lastVersion) {
this.lastVersion = lastVersion;
this.txScope = ChangeTracking.GetSnapshotScope();
var validV = ChangeTracking.GetValidVersionForAll(dataContext);
baseline = lastVersion < validV;
currentVersion = ChangeTracking.GetCurrentVersion(dataContext);
}We take in the last version, then initialize a SnapshotScope. We get the minimum valid version and see if we're going to have to generate a baseline (re-init) or not. Next, we grab the current version of the database, so consumers can save the version for when they sync up next.
To get changed keys, you can do this: ChangeTracking.GetChangedKeys<string>(dataContext, "Accounts", "AccountName", lastVersion, System.Data.Linq.ChangeAction.Delete);
This will give you an enumeration of all the Deleted keys; use other ChangeActions to get Insert or Updated. There's also a filter (SQL string) to limit further.
To get changed _items_, you can pass in a Queryable, like this: ChangeTracking.GetChangedItems<Account>(dataContext, dataContext.Accounts.Where(a=>a.Balance>10), "Accounts", "AccountName", lastVersion);
The code should (seems to work for me) figure out your query and inject the JOIN to the CHANGETABLE function. The code is linked at the end of this article. Some of the functions use a Tuple type; if you don't have it, I've posted it elsewhere on this site. Or, you can delete those methods; they are only for 2-key tables. ChangeTracking.cs.txt (9 KB)
|
|
Code | Misc. Technology
|
Thursday, September 18, 2008 2:03:46 AM UTC
|
Trackback
|
 Wednesday, September 17, 2008
Something I've heard often is that "F# is too complex/functional programming is too hard". This is something that sorta came up in the comments here: http://www.atrevido.net/blog/2008/09/16/Why+NOT+F.aspx.
Why is this irrelevant? You only learn a language once. You pay the learning curve cost one time; after that, you have the techniques and power at your disposal. However, you pay the cost of code every time you read or write it. Since I'm going to read and write a lot more code than number of languages I learn, I'd much, much, prefer to pay this overhead once, up front, rather than in my code each time.
Of course, it's not necessarily this simple. It's possible to design a powerful language that renders code even more difficult. Regular expressions are perhaps a nice example of this; they're often called "write only" code. Every time I do a non-trivial regexp, I'm always going back to the reference. Another example are C macros -- text-based, they quickly let you get into trouble. The design of C# runs away from this and tries to make it very difficult to write code that is "hard" to figure out -- if there's any edge case where a feature might be confusing or not work, C# tends to not allow it at all.
F# design is different. F# doesn't try to shelter users - it gives you tools and lets you decide how to use them. It makes the assumption that if you're writing a program, *you have some clue of what you're doing*. F#'s tools are still safe (compared to say, C), but sure, you can go create a mess if you'd like.
Poor code quality is *not* something that should be fixed solely via technical measures. I liken it to using web filters to make sure "employees aren't goofing off on the Internet" -- this is a policy/management issue and should be solved via administrative means. If one of my devs is spending all day on 4chan but gets work done and adds value, what do I care? Similarly, if the code quality coming out is acceptable and the solutions work correctly, I don't care if it used macros, custom operators, "difficult" code, etc. The process to make sure code quality is high (code reviews) will take care of anyone abusing language features in stupid ways.
But in truth, F# isn't actually much more complex to use. To the beginner, what seems to be "unnecessary terseness" and a lot of complicated syntax is actually a very basic system in action. Many of the "built-in" F# features such as the |> pipeline operator are defined right in the language itself. There's no magic going on -- you can create your own functionality in exactly the same way. Once you understand the basic rules, you'll see that most everything else follows them.
But at any rate, why is "easy to learn" a benefit? Sure, it's handy to promote a language if people can pick it up easily, but it's not indicitive of long-term power. True, if you have a "web developer" who's going to add a few server-side scripts, it's nice that he doesn't have to learn much. But if you're developing an application of any substance, I fail to see how these help, given the negative effects of having a "simple" language.
P.S. On my site I'm not trying to infer that F# will take over the world or that C# will go away. I've met too many "professional developers" to realise that anything that requires thinking isn't going to achieve stellar adoption. I'm simply pointing out that the reasons come down to apathy and intelligence (with respect to the learning curve; there could be other reasons as well), regardless of how politically correct one phrases it.
|
|
Code | FSharp
|
Wednesday, September 17, 2008 8:49:06 PM UTC
|
Trackback
|
 Tuesday, September 16, 2008
This is actually an open request for comments. I'm honestly interested in hearing why F# is not always the better candidate versus C#. What can C# do well that F# cannot? In nearly everything, F# seems to come out on top, as far as I can see.
Let's get these out of the way:
- Personal preference. Enough said. - In beta. Enough said. - Legacy code. Sure, if you have a project in C#, it may not make too much sense to switch mid-way. - Management. Enough said. - No benefit. This is simply lack of education and needs to be addressed separately. - F#'s too hard/it's hard to hire F# devs. This is a non-issue that is a separate topic. In summary, anyone worth hiring for C# work should be able to handle F#. [Exception being a very small deadline with an existing team...]
The only code reason I've seen is heavy native interop/pointer work. F# seems to be slightly more verbose than C# in this case. It's not much more, but I could see if you're doing just pointer code then it could get annoying. (Interestingly enough, F# COM interop is much nicer than C# because it supports named and optional parameters (http://blogs.msdn.com/dsyme/archive/2008/05/02/full-release-notes-for-f-1-9-4.aspx, search for "chart")...)
What other reasons are there for C# over F#?
Edit: Good point in the comments about C# being a standard with open source implementations. That could be a big issue for some. Another good point is the current lack of tool support (like ClickOnce, ASPX and WPF designers, etc.). I don't see any intrinsic reason F# wouldn't have those, except for limited resources.
|
|
Code | FSharp
|
Tuesday, September 16, 2008 5:06:28 AM UTC
|
Trackback
|
When specifying a connection string to use with LINQ-to-SQL, make sure you "correctly" case MultipleActiveResultSets. If you have something like this: "Server=(local);Database=master;Integrated Security=true;App=dcdemo;MultipleActiveResultsets=true", LINQ-to-SQL will determine MARS is disabled even though it is not.
This is because inside the LINQ-to-SQL implementation, a normal String.Contains is performed on the connection string. Since this is an ordinal compare, it won't find MARS turned on if you spell it differently. Without MARS enabled, if you execute multiple queries on a single DataContext, it will force the outstanding queries to buffer. This means that instead of a nice lazy reading from the SQL server, you'll end up bringing it all into local memory.
More info here: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=366444
|
|
Code
|
Tuesday, September 16, 2008 5:02:00 AM UTC
|
Trackback
|
 Tuesday, September 02, 2008
|
There are other great books out there such as Expert F#.
The F# Dev center has links to many other "learn F#" articles. All of
these are great.
But, something I found helpful is going "purely functional", and
Haskell is the perfect vehicle. When you're forced to think only functional,
and don't have the other "escapes" F# has, you bend your mind into
understanding how you can accomplish things without using mutation or
object-orientation.
The downside of Haskell is that many resources seem to be very challenging to
get into. There's no doubt that the learning curve for Haskell can be tough. On
top of that, many materials tend to dive right into monads and it tends to end
up too scary. I've even bought several other good books on functional
programming, but none of them were easily approachable. (They have good
content, but you can't start from zero by using them.)
Enter Real World Haskell. This
is a *very* easy to follow book and really drives functional programming home.
It doesn’t assume you know anything about functional programming at all, so the
learning curve is a gentle slope.
Even better? It's completely available online, so you can
start reading it right
now! Plus, it has reader-submitted comments which are of tremendous use, as
they ask and answer many common questions that might arise as you read along,
without interfering with the flow. You can read the entire book here: http://book.realworldhaskell.org/read/
[But buy it to support the excellent work the authors have done!]
I've found that my F# skills have gone up tremendously by reading Real World
Haskell. For instance, I "sorta" understood F#'s computation
expressions and builder. Say, enough to use them -- that's easy, like most
things in F#), but understanding the concepts behind them? Starting to learn
Haskell really brings the understanding around. This isn't to say that you'll
eschew mutation and OO in F# -- such concepts can be very useful (and increase
performance on the CLR). But at least you'll know when a more elegant solution
is available.
(Plus, it's fun! As someone in #haskell on freenode put it to me:
"Learning Haskell will f*ck with your brain, and you'll like it.")
|
|
Code | FSharp
|
Tuesday, September 02, 2008 4:00:06 AM UTC
|
Trackback
|
Managed code? In MY softswitch? It's more common than you think.
A while back, I tried creating a mono plugin for Asterisk. The goal being that'd you'd be able to write in-process apps in decent languages, rather than resorting to C. Well, there were no standards of how functions operated (i.e., who's responsible for memory), and my requests to standardize these were met with hostility. (Actually, when I asked why they didn't refactor some stuff, like the multi-thousand-line switch statements, I was told "refactoring doesn't exist for C"... sigh.) But the real showstopper was that we couldn't figure out how to get Asterisk to play nice with mono as far as threads go. I had a very active Asterisk developer work on it with me, and he pretty much told me it wasn't going to work. Oh well.
When I stopped really being involved with Asterisk, I had seen a couple big Asterisk developers leave to start FreeSWITCH. It was mainly an idea at that point, to do things right and build a scalable, clean system. Well, fast forward a few years and FreeSWITCH has really come far. You can go read their site for more details, but it's a more flexible, scalable, and vastly cleaner VoIP platform. That's why, at v1.0.1, it already supports UDP, TCP, TLS, SRTP, IPv6, wideband codecs, and more. Oh, and it runs cross-platform, including Windows.
But the really great thing about FS is that it was designed to be modular from the beginning. And, it was designed to allow people build apps into it. It has some nice out-of-process extensibility, think Asterisk Manager and AGI, without the suck. [I wonder how many * flames I'm gonna get?] But also of interest, they designed an app API from the start. It's written in C++, and SWIG friendly so you can quickly add other languages (Javascript and Lua seem to be the most popular).
Well, the thought of running interpreted stuff in-process disgusted me, so I immediately set out to try to add Mono support. Much to my surprise, the FS team was extremely supportive. They helped me figure out all the bits of FS and the API I needed. In fact, one of the project leads told me, "Hell, if you're gonna write mod_mono, we'll give you checkin support right now.". A short bit later, we had mod_mono working!
Not satisfied with doing just apps, I turned to doing a full integration. A bit of SWIGwork later, and I had the entire FreeSWITCH header files SWIG'd and C# accessible. I found a few APIs that didn't import (varargs stuff, I think), but the FS team helped add some different methods to work around that.
The Mono side was pretty straightforward. We write a C/C++ module for FS that gets Mono up and running. Then it kicks off mod_mono_managed, which actually loads modules, runs initialization code, etc. The biggest problem I ran into was a problem between SWIG and Mono. Mono would attempt to free strings with g_free, crashing on Windows. I wrote a SWIG-C# post-processor to tweak the SWIG code to avoid it; I'm not sure it's accurate, but we haven't noticed issues so far. A few things we ran into were quickly cleared up by the awesome people #mono. This week we'll be testing and make sure it's fixed in Mono 2.0.
So, the bottom line is that you can write any sort of module for FreeSWITCH, from simple apps and API functions, down to a full codec or endpoint, all in managed code (though, the interop might not be pretty sometimes). I've tried some simple stuff out in C#, F#, and Javascript (JScript .NET), and it all works fine. The code is in the FS SVN, under /freeswitch/src/mod/languages/mod_mono and mod_mono_managed. It's not part of the official build yet, so there may be a bit of work involved in getting it going. But I have heard from other people that they've gotten it working. Some info is here: http://wiki.freeswitch.org/wiki/Mod_mono -- Right now, we've only tested on Mono 1.9.1, but we're going to only support 2.0 as of very soon. (F# only supports 2.0, so earlier versions are irrelevant to my interests :).)
This is exciting for us, as it allows us to build *safe* applications that run in-process with the switch. But, unlike the embedded scripting languages, we get top-notch performance and access to complete libraries. We're combining this in-process approach with out-of-process (Event Socket, outbound) to get a robust and very scalable system. For our particular application, we have several GB of decision data that we keep in RAM on separate servers (which is in turn sync'd to SQL Server 2008, via a proprietary change replication system). For obvious reasons, we didn't want that memory being stuck in the FS process. Having Mono on both sides allows us to share code between the different systems, while still getting optimizations for both environments.
You can email me: mgg AT a t r e v i d o _ net or use the chat widget on the on my site if you have questions or problems getting it going.
I'll post a follow up once it's in the official build.
|
|
FreeSWITCH | VoIP
|
Tuesday, September 02, 2008 2:04:38 AM UTC
|
Trackback
|
 Sunday, August 31, 2008
Many times when I talk to a pro-dynamic typing person, they bring up duck typing. And when I say that duck typing could be resolved statically, I usually get wierd looks, or worse. Well F# exposes static duck typing to users. At least, using the definition that C# uses for duck typing of foreach and collection initalizers. (Yes, of course its a compiler feature and not true CLR/runtime checking.) I'm not promoting this, just pointing it out for fun.
F# allows inline values to accept "statically resolved type
variables". The F# specification says (§5.1.2):
A type of the form ^ident is a statically resolved variable type. A fresh type inference variable is created and added to the type inference environment (see §14.6). This type variable is tagged with an attribute indicating it may not be generalized except at inline definitions (see §14.7), and likewise any type variable with which it is equated via a type inference equation may similarly not be generalized.
At the end of this post I have a simple example to help understand this kind of type variable. But more interesting is a another constraint you can apply to such type variables. §5.1.5.3 Member Constraints: "A constraint of the form (typar or ... or typar) : (member-sig) is an explicit member constraint." But, inside the the F# library, this form is used with function application! For example, the char function is defined:
let inline char (x: ^a) = (^a : (static member ToChar: ^a -> char) (x)) // Function application! ...<snip /> -- I removed all the special case and inline IL code as its irrelevant for this post
Well, if we have member constraints with function application... we have "statically typed duck typing":
let inline speak (a: ^a) =
let x = (^a : (member speak: unit -> string) (a))
printfn "It said: %s" x
let y = (^a : (member talk: unit -> string) (a))
printfn "Then it said %s" y
type duck() =
member x.speak() = "quack"
member x.talk() = "quackity quack"
type dog() =
member x.speak() = "woof"
member x.talk() = "arrrr"
let x = new duck()
let y = new dog()
speak x
speak y
Outputs:
It said: quack Then it said quackity quack It said: woof Then it said arrrr
The restriction is that you have to use inline to get generalization*. If it's not inline, then it'll add additional constraints based on usage. If you removed inline in this case, you'd get the following:
warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type 'duck'. error FS0001: The type 'dog' is not compatible with the type 'duck'.
Inline is as it sounds - the IL code is emitted inline, which is obviously a drawback in many cases. But that's the only way it can work - it has to statically know what types and compile the right method info into the binary. I suppose it'd be possible for the CLR to support this intrinsically. That way, the JIT could emit much more optimized code, versus creating a new method for reach type. I don't know dynamic languages well enough to know if this would be at all a help for interop.
*Here's a simple example to demonstrate the difference between 'a and ^a type parameters generalization.
> let id (a : 'a) = a;; val id : 'a -> 'a
> id 1, id "hi";; val it : int * string = (1, "hi") // Good, it's generic
> let id (a : ^a) = a;; let id (a : ^a) = a;; -------------^^ stdin(8,14): warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type 'obj'.
val id : obj -> obj
> id 1, id "hi";; val it : obj * obj = (1, "hi") // Constrained to obj - not generic
> let inline id (a : ^a) = a;; val inline id : ^a -> ^a
> id 1, id "hi";; val it : int * string = (1, "hi") // Since it's inline, it's generic
|
|
FSharp
|
Sunday, August 31, 2008 1:14:34 AM UTC
|
Trackback
|
 Saturday, August 30, 2008
I find myself using "Comment Selection" often as I hack up quick scripts. Before the F# CTP, doing "Comment Selection" (Ctrl-K, Ctrl-C) would simply add (* *) around the selection. This makes it hard to uncomment specific lines. Now it goes and adds // in front of each line. Small things like this, in aggregate, decide a great IDE. For as much as I dislike some C# language decisions, their code editor is the best of anything I've ever seen.
Oh yea, the IntelliSense is also now WAY better. What's still missing is the "always active autocomplete", although I suspect this is harder in F#'s #light syntax than in C#.
|
|
FSharp
|
Saturday, August 30, 2008 6:10:59 PM UTC
|
Trackback
|
 Friday, August 29, 2008
Came across this: http://michaelcurbanski.com/log/2008/08/29/functional-programmers-hate-events/
His main point is that async total sucks, but that "Events don’t necessarily make async code tragically unreadable!" As a demonstration, he shows some simple async HTTP code without full or exception continuations. His code just enforces my point.
At any rate, yes, sure, if your continuation code isn't too related to your calling code, events can work. I mentioned this in my post: "events are a bad choice for code that is not loosely coupled" followed with "sometimes a simple delegate field would be a better choice". Indeed, looking at Mike's sample code, it seems as if using a simple delegate field would allow some nice refactoring.
But a point of the Event-based Asynchronous Pattern is, and I quote, to "Wait for resources to become available without stopping ("hanging") your application". So basically, you want to take an existing method, say, in response to a user action, but you can't let it block. This is exactly perfect for a continuation based approach and not so much for a loosely-coupled event-based approach. The act of "firing" an event should indicate that you're letting _other listeners_ (notice the plural) know when you did something.
More on when events are appropriate: Say you're listening for SNMP messages and when you receive one, you let "everyone" know that you did. You don't care what they do with the result, and they just go off on their own. Events can work. Or, take, for example, the BackgroundWorker. The BackgroundWorker doesn't help thread your blocking code, it just pushes the block to a background thread you don't care about. Your HTTP code will still be all sync, and you'll still burn a thread. BackgroundWorker main help is that it coordinates back to your "UI" thread, since many UI frameworks have strong thread affinity and will crash otherwise.
But that was the whole point The event async pattern, specifically in things like Silverlight, is completely aimed at *not letting the thread block*. That's the _only_ problem it is trying to solve. Silverlight only forces this because the main thread is the UI thread, and they won't want the browser hanging by dumb apps that don't put the block on a background thread. If they didn't want to do continuations, they could have at least kept the sync APIs, and thrown an exception if called from the main thread (thus letting people who know what they're doing not have to deal with the ugly event syntax).
BTW, F# kicks the crap out of your language I didn't mention it in my previous event post, but F#'s computation expressions let you deal with continuations in a totally sexy way. H.H. Don Syme, writes about it here: Introducing F# Asynchronous Workflows. You learn F# if you don't know it. But just to demonstrate, here's an example from that introduction:
let AsyncHttp(url:string) =
async { // Create the web request object
let req = WebRequest.Create(url)
// Get the response, asynchronously
let! rsp = req.GetResponseAsync()
// Grab the response stream and a reader. Clean up when we're done
use stream = rsp.GetResponseStream()
use reader = new System.IO.StreamReader(stream)
// synchronous read-to-end
return reader.ReadToEnd() }
The let! binding handles things asynchronously; the rest of the body becomes a continuation. If that isn't superior to any C# approach and doesn't make async easy, I don't know what would.
|
|
Code | FSharp
|
Friday, August 29, 2008 9:03:55 PM UTC
|
Trackback
|
|
|