Every once in a while, I like to pretend that I can reload past mindsets like Smalltalk images. Today's story is about a dynamic programming language.
It loaded libraries at run-time. It sat at a level of abstraction from the actual computing hardware: there were no pointers. Memory management happened during execution in an automatic mechanism. Characters weren't single bytes. Checks of all kinds took place as code ran, affording a minimum of "protection". For smaller programs, start-up time itself was a performance constraint. Method dispatch wasn't fully resolved until the time of the call. Commentators often complained about the costs of all this dynamism.
Naturally, I'm describing Java as it was viewed a handful of years ago. This is why it's so amusing to hear that Java has somehow turned into the static language standard-bearer. At least where I was working, the original competitor to Java Servlets in the Web domain was Perl CGI, not C or C++. It was a battle between two dynamic options, in which greater simplicity of string manipulation and memory management trumped other concerns. Java was the company-pushed "compromise" solution that had better threading, Unicode, fairly easy C-like syntax, and so on, yet without some of the traditional downsides of the static languages. In retrospect, other languages could have filled that niche quite well (especially with a tweak or two), but lacked comparable levels of publicity, support, education, and engineering. Regardless of accuracy, the negative perceptions of Java's potential opposition were sufficient to leave an opening. As much as academic and research programmers would prefer it to be the case, programming languages aren't chosen based solely on the sophistication and self-consistency of syntax and semantics.
I'm not seriously proposing that the possibilities for dynamism in Java are comparable to the languages usually labeled as "dynamic". I'm only reiterating the truism that all the aspects of a language and/or its execution "platform", including and beyond the type system of its variables, are on a continuum between static and dynamic.
Showing posts with label Programming Languages In Specific. Show all posts
Showing posts with label Programming Languages In Specific. Show all posts
Friday, July 22, 2011
Friday, May 27, 2011
peeve no. 263 is offhand Java bashing
It's a sign of immature writing to insist on inserting opinions and extra comments. Within opinionated persuasive essays (or blog rants), this is an expected practice because it's the whole point. Within a tutorial, it's an irritating distraction. If you're writing disinterested and objective prose about a technological topic, then it's...not...about...you!
When someone's stated goal is to educate, as opposed to spreading a point of view, side-swipes at programming languages should be left out. There's certainly a time and place to "fight the good fight" for your faction, but not by dumping stray sentences in the middle of a how-to on neutral ground. I understand, Advanced Technical Writer, that you're eager to give off the impression that you're an independent thinker of exquisite taste. Why not fully express your sophisticated perspective into a separate long-form document, rather than confining it to a cryptic handful of sentences or footnotes in everything you write? Tossing off some quick one-sided insults doesn't do justice to yourself or the reader. Advocate in your advocacy articles. Propagandize in your propaganda.
When someone's stated goal is to educate, as opposed to spreading a point of view, side-swipes at programming languages should be left out. There's certainly a time and place to "fight the good fight" for your faction, but not by dumping stray sentences in the middle of a how-to on neutral ground. I understand, Advanced Technical Writer, that you're eager to give off the impression that you're an independent thinker of exquisite taste. Why not fully express your sophisticated perspective into a separate long-form document, rather than confining it to a cryptic handful of sentences or footnotes in everything you write? Tossing off some quick one-sided insults doesn't do justice to yourself or the reader. Advocate in your advocacy articles. Propagandize in your propaganda.
I would've written this example shorter, but Java is awful, am-I-right? Now watch me apply the words "noise" and "clutter" to perfectly understandable and correct syntax. Isn't a shame that I used an anonymous class here, when other languages (wink-wink, nudge-nudge) offer different possibilities? I apologize for writing loops and not overriding operators; my example language ties my hands so tight that it burns. Sorry about these checked exceptions ruining my 'sunny-scenario-only-dear-bob-don't-copy-it-as-is' code sample. Please don't laugh at the parentheses in my 'internal DSL', I did the best I could with the terrible tools available. Oh, how I long to have avoided that well-known design pattern through the deep meta-programming magicks that you naive mortals cannot comprehend. And the explicit data types torture me so...
Sunday, November 07, 2010
shared state is not hard to find in Javascript
...and it's called "DOM" (the webpage Document Object Model). State is shared between pieces of code whenever all the pieces may read and write to it, and that applies to the DOM. No declarations are necessary; neither reads nor writes require express permission or coordination. In this freewheeling land known as the "document", anything is up for grabs.
Yet why does it matter, given that dynamic changes to the DOM are a huge part of Javascript's appeal? It matters because any shared state, by its nature, can lead to problems for the unwary, especially as size and complexity grow.
- If various Javascript functions touch the DOM, then those functions may cease working properly whenever the page changes structure. One change, no matter how trivial, has the potential to mess up code in several places at once. For instance, say that two tabs switch order...
- Similarly, whenever there's an algorithmic adjustment, all the functions that affect relevant individual parts of the DOM must be spotted and redone. Rounding and displaying four decimal places, but only in inputs for numerical data of a particular category, means code changes for everywhere that those input values are set or read.
- My impression from some blogs is that people are feeling skeptical about the actual prospect of code reuse in many circumstances, but it's still a worthy ideal. As always shared state is a hindrance to reusability simply because it isn't parameterized. A function that includes an instruction to remove a style class from the element of id "last_name" is pretty difficult to reuse elsewhere.
- On the other hand, shared state opens up the possibility of no-hassle collaboration. Function A (assuming a better name!) can take on the responsibility of setting up the shared state in some way. Then function B can do some other task to the shared state, any time after A has recently run. But function C can run directly after either A or B. So function A must leave the shared state in acceptable configurations for either B or C, and B must also account for C. Of course, if there's a new special data value in the shared state that affects what C must do, one must be careful to modify both A and B to set it accordingly. Hence, although shared state makes it highly convenient to intertwine the operation of many pieces of code, the intertwining also greatly reduces readability! It's much easier to analyze separate pieces of code with well-defined connection points.
- Furthermore, implicit shared-state dependencies don't combine well with asynchronous execution. Javascript doesn't have concurrent execution (i.e. multithreading), but it's certainly possible for separate pieces of code, such as callbacks for clicks and timers and network requests, to execute in an unpredictable order. So while there won't be deadlocks in the traditional sense, unwitting callbacks that fire in an unintended sequence could leave the DOM in a useless or false form after the dust clears.
Many techniques could apply to mitigation of the shared state known as DOM. For information storage, rely on variables residing in purposeful scopes rather than DOM elements and/or attributes. Treat the DOM as an end, instead of intermediate, data format. Isolate the code that handles the DOM from the code that processes data. DOM modifications that always happen together should be collected into a single function with an appropriate abstract/semantic name.
Not all of the shared state in an application consists of variables. Whether log file, database, or DOM, access logic should be carefully considered to avoid maintenance headaches.
Not all of the shared state in an application consists of variables. Whether log file, database, or DOM, access logic should be carefully considered to avoid maintenance headaches.
Thursday, October 08, 2009
LINQ has your Schwartzian transform right here...
I was looking around for how to do a decorate-sort-undecorate in .Net. Eventually I realized (yeah, yeah, sometimes I'm slow to catch on) that the LINQ "orderby" clause actually makes it incredibly easy. For instance, if you had some table rows from a database query that you needed to sort according to how the values of one of the columns are ordered in an arbitrary external collection...
var sortedRows = from rw in queryResults.AsEnumerable()
orderby externalCollection.IndexOf((string) rw["columnName"])
select rw;
Oh brave new world, that has such query clauses in it! Back when I first read about the Schwartzian transform in Perl, with its hot "map-on-map" action, it took a little while for me to decipher it (my education up to that point had been almost entirely in the imperative paradigm with some elementary OO dashed in).
Between this and not having to learn about pointers, either, programmers who start out today have it too easy. Toss 'em in the C, I say...
UPDATE: Old news. Obviously, others have noticed this long before, and more importantly taken the steps of empirically confirming that LINQ does a Schwartzian under the covers. (I just assumed it was because my mental model of LINQ is of the clauses transforming sequences into new sequences, not ever doing things in-place.)
var sortedRows = from rw in queryResults.AsEnumerable()
orderby externalCollection.IndexOf((string) rw["columnName"])
select rw;
Oh brave new world, that has such query clauses in it! Back when I first read about the Schwartzian transform in Perl, with its hot "map-on-map" action, it took a little while for me to decipher it (my education up to that point had been almost entirely in the imperative paradigm with some elementary OO dashed in).
Between this and not having to learn about pointers, either, programmers who start out today have it too easy. Toss 'em in the C, I say...
UPDATE: Old news. Obviously, others have noticed this long before, and more importantly taken the steps of empirically confirming that LINQ does a Schwartzian under the covers. (I just assumed it was because my mental model of LINQ is of the clauses transforming sequences into new sequences, not ever doing things in-place.)
Monday, February 09, 2009
Haskell comprehension measured through WTF/min
The top compliment I can give to Real World Haskell is that it manages to finally teach me the aspects of Haskell programming that I previously assumed to be both impenetrably complicated and useless. As I read I'm also reminded of what it was like when I first tried to comprehend Haskell code. I've concluded that the most noticeable sign of greater Haskell comprehension is a noticeable drop in my WTF/min when I'm figuring out a given code example.
WTF/min is "WTFs per minute". According to a highly-linked picture, this unit is "the only valid measurement of code quality" and it's determined through code reviews. My initial experiences of Haskell definitely exhibited high WTF/min. The following are some of the past Haskell-related thoughts I can recall having at one time or another.
WTF/min is "WTFs per minute". According to a highly-linked picture, this unit is "the only valid measurement of code quality" and it's determined through code reviews. My initial experiences of Haskell definitely exhibited high WTF/min. The following are some of the past Haskell-related thoughts I can recall having at one time or another.
- Infinite lists like [1..]? WTF? Oh, lazy evaluation, right.
- Functions defined more than once? WTF? Oh, each declaration pattern matches on a different set of parameters. It's like method overloading.
- The underscore character has nothing to do with this problem domain but it's being matched against. WTF? Oh, it matches anything but discards the match.
- Why is the scoping operator "::" strewn throughout? WTF? Oh, it's being used for types, not scopes.
- Even a simple IO command like "putStrLn" has a type? WTF is "IO ()"? Oh, it's an expression with IO side-effects that evaluates to the value-that-is-not-a-value, ().
- WTF? What is this ubiquitous 'a' or 't' type everywhere? Oh, it's like the type parameters of generics or templates.
- Functions don't need "return" statements? WTF? Oh, all functions are expressions anyway.
- WTF is going on with these functions not being passed all their parameters at once? Oh, applying a function once produces another function that only needs the rest of the parameters. That'll be helpful for reusing the function in different contexts.
- This function definition doesn't have any parameters at all, and all it does is spit out the result from yet another function, a function that itself isn't being passed all the parameters it needs. WTF? Oh, "point-free" style.
- Now I understand all those -> in the types. But WTF is this extra => in front? Oh, it's sorta like a list of interfaces that must be met by the included types, so the code is tied to a minimal "contract" instead of a particular set of explicit types. That's good, but how would I set those up?...
- Ah, now this I'm sure I know. "class" and "instance" are easy. WTF?! How can that be it? Just more functions? Can't I store structured information anywhere? Oh, tuples or algebraic data types.
- I like the look of these algebraic data types with the "|" that I know from regular expressions. Unions and enums in one swell foop. WTF? How do I instantiate it? Oh, what appear to be constituent data types are actually constructor functions.
- After a value has been stuffed into the data type, how can my code possibly determine which data type constructor was used? WTF? Oh, just more pattern-matching.
- WTF? Record syntax for a data type declaration results in automatic accessor functions for any value, but we use these same function names when we're creating a new record value? Oh.
- I've acquainted with map and filter. WTF is foldr and zip and intercalate? Oh, I'll need to look over the standard list functions reference.
- What's this "seq" sitting in the middle of the code and apparently doing jack? WTF for? Oh, to escape from laziness when needed.
- WTF? How can a function name follow its first argument or a binary operator precede its first argument? Oh, `backticks` and (parentheses).
- How come there's all these string escapes in the flow of code? W...T...F? Oh, lambda. Cute.
- I've always been told that Haskell is heavily functional and pure. WTF are these do-blocks, then? Oh, monads. Wait, what?
- Functor, Monoid, MonadPlus, WTF? Oh, more typeclasses whose definitions, like that of monads, enable highly generalized processing.
- A way to gain the effects of several monads at once is to use "transformers"? WTF? Oh, when a transformer implements the monad functions it also reuses the monad functions of a passed monad.
- Finally...I know that the ($) must be doing something. But what? Why use it? WTF? Oh, low-precedence function application (so one can put together the function and its arguments, then combine them).
Tuesday, July 15, 2008
peeve no. 258 is dynlang users who disrespect Perl
Before I get my rant on, I'll do the lawyerly thing and attempt to clarify my terms to avert misunderstanding.
So I know that Perl has its problems. In fact, my encounters with Perl nowadays stem from two sources: 1) ad-hoc administrative tasks and/or data processing (but if I need to interact with one or more of standard formats, databases, JVM APIs then I switch to groovy), 2) upkeep of legacy Perl that acts either as "glue" between systems or as rough internal CGI interfaces for simple yet vital business tasks (I'd also note that the "legacy" Perl has no firm date for replacement). I'm not bothered when language cheerleaders call attention to Perl's weaknesses; this practice is hardly a new phenomenon, and when the latest critic repeats the same years-old tired refrain I can barely manage to react at all. No, what gets me worked up is when someone is dismissive, contemptuous, or mocking toward Perl, which has on numerous occasions, despite its acknowledged icky portions, served my purposes, enabled me to achieve unconventional solutions, and taught me intermediate-to-advanced programming concepts. Without Perl, I might have had to hack together a comparatively ugly combination of grep, find, sed, awk, etc., and shell script. (At the time I'm describing, pretty much the only other programming language available on the system was C or C++, and later Java.)
I'm not too irked by cheerleaders for static languages who throw rocks at Perl for fun. Their derisiveness is a subset of their general antipathy for dynamic languages. If Perl was the epitome of language design perfection then they would still pronounce it junk because of characteristics that by definition apply to any dynamic language: performance overhead, lack of mandatory type enforcement, multiple inheritance, chaotic data structures that are modifiable at will, and so on.
As the title says, the true irritants are dynamic language users who explicitly or implicitly assert that Perl is horrible, terrible. These users know the advantages (and disadvantages) of a dynamic language. They know Perl is a dynamic language. They know that they would probably rather use Perl rather than a static language to solve the same problems (okay, maybe some of them would instead use ML-family, Haskell, or statically-compiled Lisp-family--just maybe). Moreover, the reasons they give for why Perl is abominable sometimes strongly resemble the reasons static language cheerleaders give for avoiding dynamic languages altogether: too many operators and punctuation in general, syntax features that can interact in complicated ways, too few built-in data types (no "official" numbers or strings, just scalars!), the choice to use or ignore OO, special variables that affect execution, accumulated design cruft that makes some tasks too awkward or tricky. The stranger cases are dynamic language users who formerly used Perl primarily, but after changing their habits suddenly stop recognizing anything valuable about Perl at all. Perhaps they used Perl for the general benefits of a dynamic language, all the while having strong distaste for the actual "Perl-ness", and as soon as they could obtain a dynamic language without that flavor they were glad to kick it to the curb. Or (shudder) perhaps some current dynamic language users spent a long time solely in the static language camp, where they grew accustomed to decrying Perl as a mysterious, confounding mess, but after using and liking a dynamic language they continued to denounce Perl more out of habit than out of scorn for dynamism anymore.
Perl is what it is (except when it purposely breaks compatibility in some ways for Perl 6), though it does keep changing and code written using current recommended practices is superior to what you might remember. All I wish is for dynamic language users to give Perl the credit it's earned, is still earning, will earn. Stop mercilessly bashing it as if it ate your parents. But know that I join you in disliking sigils, list/scalar context distinctions, and autovivification.
- "dynlang" is 9 characters shorter than "dynamic language", the name of a fuzzy category of programming languages that allow, support, and exploit the capability to make run-time changes to a program's very structure--its data types, classes/data structures, method/function dispatch. Although program interpretation is quite better suited than compilation to implement such a capability, it's too simplistic to assume that all dynamic languages are necessarily interpreted and all static languages are necessarily compiled, and for that matter too simplistic to assume that a particular language implementation never does both. (Groovy cheerleaders are fond of mentioning that their dynamic language is compiled, while compiled Objective-C code sends object messages at run-time.)
- "Disrespect" refers to an attitude, not to an engineering-like objective evaluation of trade-offs. An example of the latter is "Java's static typing nature can result in code that is difficult to adapt to unanticipated purposes." An example of disrespect is "Java sucks. And one of the reasons it sucks, and the people who choose to use it also suck, is that the stupid types strewn throughout a class do nothing but get in the way when I just want to pass in an instance of MyTempObject, and get the idiotic compiler to stop tying my hands on my behalf". (By the way, I apologize for the inaccuracy. This example of Java disrespect is a bit too lucid and courteous to match the corresponding real statements elsewhere on the Web.)
So I know that Perl has its problems. In fact, my encounters with Perl nowadays stem from two sources: 1) ad-hoc administrative tasks and/or data processing (but if I need to interact with one or more of standard formats, databases, JVM APIs then I switch to groovy), 2) upkeep of legacy Perl that acts either as "glue" between systems or as rough internal CGI interfaces for simple yet vital business tasks (I'd also note that the "legacy" Perl has no firm date for replacement). I'm not bothered when language cheerleaders call attention to Perl's weaknesses; this practice is hardly a new phenomenon, and when the latest critic repeats the same years-old tired refrain I can barely manage to react at all. No, what gets me worked up is when someone is dismissive, contemptuous, or mocking toward Perl, which has on numerous occasions, despite its acknowledged icky portions, served my purposes, enabled me to achieve unconventional solutions, and taught me intermediate-to-advanced programming concepts. Without Perl, I might have had to hack together a comparatively ugly combination of grep, find, sed, awk, etc., and shell script. (At the time I'm describing, pretty much the only other programming language available on the system was C or C++, and later Java.)
I'm not too irked by cheerleaders for static languages who throw rocks at Perl for fun. Their derisiveness is a subset of their general antipathy for dynamic languages. If Perl was the epitome of language design perfection then they would still pronounce it junk because of characteristics that by definition apply to any dynamic language: performance overhead, lack of mandatory type enforcement, multiple inheritance, chaotic data structures that are modifiable at will, and so on.
As the title says, the true irritants are dynamic language users who explicitly or implicitly assert that Perl is horrible, terrible. These users know the advantages (and disadvantages) of a dynamic language. They know Perl is a dynamic language. They know that they would probably rather use Perl rather than a static language to solve the same problems (okay, maybe some of them would instead use ML-family, Haskell, or statically-compiled Lisp-family--just maybe). Moreover, the reasons they give for why Perl is abominable sometimes strongly resemble the reasons static language cheerleaders give for avoiding dynamic languages altogether: too many operators and punctuation in general, syntax features that can interact in complicated ways, too few built-in data types (no "official" numbers or strings, just scalars!), the choice to use or ignore OO, special variables that affect execution, accumulated design cruft that makes some tasks too awkward or tricky. The stranger cases are dynamic language users who formerly used Perl primarily, but after changing their habits suddenly stop recognizing anything valuable about Perl at all. Perhaps they used Perl for the general benefits of a dynamic language, all the while having strong distaste for the actual "Perl-ness", and as soon as they could obtain a dynamic language without that flavor they were glad to kick it to the curb. Or (shudder) perhaps some current dynamic language users spent a long time solely in the static language camp, where they grew accustomed to decrying Perl as a mysterious, confounding mess, but after using and liking a dynamic language they continued to denounce Perl more out of habit than out of scorn for dynamism anymore.
Perl is what it is (except when it purposely breaks compatibility in some ways for Perl 6), though it does keep changing and code written using current recommended practices is superior to what you might remember. All I wish is for dynamic language users to give Perl the credit it's earned, is still earning, will earn. Stop mercilessly bashing it as if it ate your parents. But know that I join you in disliking sigils, list/scalar context distinctions, and autovivification.
Tuesday, August 07, 2007
good language for internal DSLs
It's tiny, mature, and performs well. Its syntax is minimal and straightforward, but it still supports a number of fancy features. It's embeddable. It's portable. It's extensible through a mechanism somewhat like a meta-object protocol. Its C interface is remarkably convenient.
It's Lua. You didn't think I was describing Ruby, did you?
It's Lua. You didn't think I was describing Ruby, did you?
Monday, August 06, 2007
shifting programming metaphors
Someone at work has a habit of using "Fortran" as a synonym for "simple, imperative-style programming", regardless of the specific language: "Fortran Java", for instance, means clumping all code into the main method.
What makes this amusing is that Fortran hasn't been sitting still since he last used it. Even Fortran has objects now.
What makes this amusing is that Fortran hasn't been sitting still since he last used it. Even Fortran has objects now.
Sunday, July 15, 2007
C reflections
I did some work in C/C++ recently, which has left me feeling reflective. I haven't done a lot in C/C++, but I know it well enough to accomplish the goals I must. C has a special place in my memories because it was one of, if not the very first of, the truly general-purpose and professional-strength programming languages I learned about. I'm frightened at the thought of people who say they wish to study the discipline and craft of computer programming but don't know C except by reputation.
What makes that thought frightening is C's continuing vital importance. Just as human history is the invisible-but-pervasive factor that shapes present civilization and culture, so C (specifically software written in C/C++) is the invisible-but-pervasive factor underlying the present software development ecosystem. Show me an OS, a compiler, an IDE, a JVM, a device driver, and I'll show you C's influence.
C's centrality and effectiveness stem directly from its ability to map so closely onto the machine which will execute it, but still abstract the programmer from the excruciating details of the actual hardware--registers, memory segments, byte-order, opcodes. In fact, C/C++ compilers have gotten so adept at bridging the gap, an inexpert programmer who tries to do it himself may achieve a decrease in the optimization level. I know alternatives to C have come along (often not too different from the king), but C's own success has seemingly doomed it to be the de-facto, default choice in its niche.
However, to do real work in C/C++ is to be constantly aware of its balancing act between the structure of the machine and the structure of the problem domain. It's not long after the stage of thinking "I need to work closely with the machine" and therefore choosing C/C++, to the stage of thinking "geez, this is irritating to write all these steps" and therefore breaking out the standard library or one of the multitude of other libraries. I wonder to what degree just the lack of sophisticated built-in string support caused the rise of alternative languages to C for some uses. Then there's the lack of sophisticated built-in data structures such as lists and maps, which are so widely applicable it seems silly to mention it. I caught myself missing stack traces for uncaught exceptions, or even any exception-throwing at all. It's no surprise that some libraries or toolkits provide such a comprehensive cocoon of functions and macros for the programmer that the result feels like a dialect (smart pointers? vectors?).
The tradeoff, naturally, is that since none of those extra libraries or language features must be used in any given program, the overhead or complexity aren't mandatory either. And there's something satisfying in using a language that connects the programmer to the machine. The language has abundant evidence that the program is intended for a computer and not a "theoretical Turing Machine": pointers, structs which are nothing more than organizational units for groups of variables, variables that refer to memory locations rather than objects, the capability to interpret memory contents in multiple ways (hence weak-typing), void * functions for futzing with memory directly. It can certainly be tricky and even error-prone sometimes, but the "garbage in, garbage out" principle rules all. Many people are both more experienced and more skilled at it than I am (I'm more of a math/logic/language tinkerer than a hardware tinkerer).
For me, C is the emblematic programming language, because it unapologetically bridges human thought and machine computation. Someone who can write effective C is someone who can straddle both realms. Try too hard to make C code like human thought, and the program may run horribly (unnecessary recursion, for example, or number overflows?). But try too hard to tailor C code to the machine, and the program may become an inflexible and devilishly cryptic tangle. Get to know C/C++, grasshopper. Folks are fond of saying how Lisp leads to " 'aha' moments". The melding of mind and machine in C code may yield similar " 'aha' moments". At the very least, you may gain a deeper appreciation for what compilers/interpreters are actually doing for you. And if nothing else, having just reading-fluency with C/C++ is pragmatic, because it's still alive and kickin' in the "enterprise", in "legacy" code anyway. C/C++ also happens to be extremely important in the FLOSS world, thanks to this "gcc" thing you may have heard of (during my Gentoo phase, gcc may have been the largest single consumer of CPU cycles).
What makes that thought frightening is C's continuing vital importance. Just as human history is the invisible-but-pervasive factor that shapes present civilization and culture, so C (specifically software written in C/C++) is the invisible-but-pervasive factor underlying the present software development ecosystem. Show me an OS, a compiler, an IDE, a JVM, a device driver, and I'll show you C's influence.
C's centrality and effectiveness stem directly from its ability to map so closely onto the machine which will execute it, but still abstract the programmer from the excruciating details of the actual hardware--registers, memory segments, byte-order, opcodes. In fact, C/C++ compilers have gotten so adept at bridging the gap, an inexpert programmer who tries to do it himself may achieve a decrease in the optimization level. I know alternatives to C have come along (often not too different from the king), but C's own success has seemingly doomed it to be the de-facto, default choice in its niche.
However, to do real work in C/C++ is to be constantly aware of its balancing act between the structure of the machine and the structure of the problem domain. It's not long after the stage of thinking "I need to work closely with the machine" and therefore choosing C/C++, to the stage of thinking "geez, this is irritating to write all these steps" and therefore breaking out the standard library or one of the multitude of other libraries. I wonder to what degree just the lack of sophisticated built-in string support caused the rise of alternative languages to C for some uses. Then there's the lack of sophisticated built-in data structures such as lists and maps, which are so widely applicable it seems silly to mention it. I caught myself missing stack traces for uncaught exceptions, or even any exception-throwing at all. It's no surprise that some libraries or toolkits provide such a comprehensive cocoon of functions and macros for the programmer that the result feels like a dialect (smart pointers? vectors?).
The tradeoff, naturally, is that since none of those extra libraries or language features must be used in any given program, the overhead or complexity aren't mandatory either. And there's something satisfying in using a language that connects the programmer to the machine. The language has abundant evidence that the program is intended for a computer and not a "theoretical Turing Machine": pointers, structs which are nothing more than organizational units for groups of variables, variables that refer to memory locations rather than objects, the capability to interpret memory contents in multiple ways (hence weak-typing), void * functions for futzing with memory directly. It can certainly be tricky and even error-prone sometimes, but the "garbage in, garbage out" principle rules all. Many people are both more experienced and more skilled at it than I am (I'm more of a math/logic/language tinkerer than a hardware tinkerer).
For me, C is the emblematic programming language, because it unapologetically bridges human thought and machine computation. Someone who can write effective C is someone who can straddle both realms. Try too hard to make C code like human thought, and the program may run horribly (unnecessary recursion, for example, or number overflows?). But try too hard to tailor C code to the machine, and the program may become an inflexible and devilishly cryptic tangle. Get to know C/C++, grasshopper. Folks are fond of saying how Lisp leads to " 'aha' moments". The melding of mind and machine in C code may yield similar " 'aha' moments". At the very least, you may gain a deeper appreciation for what compilers/interpreters are actually doing for you. And if nothing else, having just reading-fluency with C/C++ is pragmatic, because it's still alive and kickin' in the "enterprise", in "legacy" code anyway. C/C++ also happens to be extremely important in the FLOSS world, thanks to this "gcc" thing you may have heard of (during my Gentoo phase, gcc may have been the largest single consumer of CPU cycles).
Tuesday, June 19, 2007
Python 3000 Status Update
Link here. I admit to not currently using any implementation of Python for work or play. Many months ago I experimented with Jython for some job tasks, but since then the night-and-day difference in momentum between the Jython and Groovy projects has led the decision-makers to prefer Groovy. Either way, most of the code I work on remains Java or C#.
Nevertheless, I'm glad to see Python 3000 is almost there, and just as glad to see that some of Python's little quirks will be corrected. As Guido explains, the changes are intended to make Python more pythonic! Die, '<>' operator, die!
Yay for Unicode support, with bonus points for properly crediting Java as the design inspiration. I wonder how restless the natives may become when they notice that Python 3000 has separate object hierarchies for streams and bytes, abstract base classes, "annotated" function signatures, "print" as a function...
Nevertheless, I'm glad to see Python 3000 is almost there, and just as glad to see that some of Python's little quirks will be corrected. As Guido explains, the changes are intended to make Python more pythonic! Die, '<>' operator, die!
Yay for Unicode support, with bonus points for properly crediting Java as the design inspiration. I wonder how restless the natives may become when they notice that Python 3000 has separate object hierarchies for streams and bytes, abstract base classes, "annotated" function signatures, "print" as a function...
Tuesday, November 21, 2006
subjective impressions of Objective-C
After I read a comment on some blog expressing high praise for the features of Objective-C, I've been going through some introductory materials found by Google. I must say that the experience has been eerie. It's almost as if someone was storing C and Smalltalk on the same volume, there was some corruption, and the recovered file(s) ended up mashed together. I confess to knowing about as much about Smalltalk as Objective-C (that is, close to nil - HA, I made a funny!), but the resemblance is obvious. I think I have a clearer understanding of how people can assert() that Java is C++ going back to its Smalltalk roots, but not quite getting there.
First, the parts I like. The Categories capability is intriguing. It reminds me of the roles that are part of Perl 6. I also like the choices the language offers: either use objects with a type of "id" and send messages to whatever object you like, or use static object types and Protocols when that level of dynamic behavior is undesireable or unnecessary. Even better, Objective-C inherits the high-performing "close-to-the-metal" compilation of C, with an extra library that handles the fancy object tricks at runtime. I kept wondering why I hadn't heard more about this language, and why it didn't seem to be in more widespread use (by the way, I own nothing made by Apple).
Then my reading uncovered several justifiable reasons why Objective-C didn't hit the big time, at least on the scale of Java or C++. It doesn't have a true standard, which means that the chance of multiple entities implementing it is correspondingly lower. On the other hand, one open implementation can act as a de facto standard, so this criticism may not apply to GNUstep. Another problem for me is the syntax. Punctuation ([ : - +) is used in ways that I've never seen before. Perl is worse in this way, and I suppose that programmers who seriously use Objective-C become accustomed. Something else that bugs me is Objective-C's strong association with specific framework(s). A standard library is fine, of course, in order for a language to be useful, but I expect there to be competing libraries or toolkits for anything more complicated. I also wish that Objective-C was implemented on a common platform (Parrot, CLR, JVM), which would get rid of this issue. But then Objective-C would be competing with languages that have dynamically-typed OO as well as convenient syntax niceties that elevate the programmer above C's level. Frankly, although Objective-C is fascinating to study, I don't think it fits any important niches anymore, except possibly the niche currently occupied by C++. If you need Smalltalk-like abilities, use Smalltalk. If you just want to crunch numbers or strings at a high level of abstraction, use OCaml or Haskell. If you deeply need code that performs well, use C with a good compiler or even assembly. If you just need to solve a common problem, use a scripting language.
Here are some of the links I found:
First, the parts I like. The Categories capability is intriguing. It reminds me of the roles that are part of Perl 6. I also like the choices the language offers: either use objects with a type of "id" and send messages to whatever object you like, or use static object types and Protocols when that level of dynamic behavior is undesireable or unnecessary. Even better, Objective-C inherits the high-performing "close-to-the-metal" compilation of C, with an extra library that handles the fancy object tricks at runtime. I kept wondering why I hadn't heard more about this language, and why it didn't seem to be in more widespread use (by the way, I own nothing made by Apple).
Then my reading uncovered several justifiable reasons why Objective-C didn't hit the big time, at least on the scale of Java or C++. It doesn't have a true standard, which means that the chance of multiple entities implementing it is correspondingly lower. On the other hand, one open implementation can act as a de facto standard, so this criticism may not apply to GNUstep. Another problem for me is the syntax. Punctuation ([ : - +) is used in ways that I've never seen before. Perl is worse in this way, and I suppose that programmers who seriously use Objective-C become accustomed. Something else that bugs me is Objective-C's strong association with specific framework(s). A standard library is fine, of course, in order for a language to be useful, but I expect there to be competing libraries or toolkits for anything more complicated. I also wish that Objective-C was implemented on a common platform (Parrot, CLR, JVM), which would get rid of this issue. But then Objective-C would be competing with languages that have dynamically-typed OO as well as convenient syntax niceties that elevate the programmer above C's level. Frankly, although Objective-C is fascinating to study, I don't think it fits any important niches anymore, except possibly the niche currently occupied by C++. If you need Smalltalk-like abilities, use Smalltalk. If you just want to crunch numbers or strings at a high level of abstraction, use OCaml or Haskell. If you deeply need code that performs well, use C with a good compiler or even assembly. If you just need to solve a common problem, use a scripting language.
Here are some of the links I found:
- Love, Hate and Objective-C. This is a balanced evaluation from someone who knows much more about Objective-C than me.
- Python-Objective-C bridge. Any project that bridges languages is worth a gold star.
- Objective-C Beginner's Guide. Nice page that just shows a snippet of Objective-C example code for each signficant feature, followed by an explanation of the snippet. Every language should have a page like this, but I can see how it might be too terse for some people.
- Apple documentation for Objective-C. (pdf) All you need or want to know, from the source. I didn't read the entire thing.
- Behind the Scenes of Objective-C 2.0. What the upcoming version of Objective-C will have. I can't imagine working without garbage collection.
Saturday, September 23, 2006
hackers and...musicians?
I recently found the Choon programming language page. To quote:
Unrelated observations from killing time by watching old Smallville shows in syndication: 1) crazy Joe Davola is one of the producers, 2) Evangelline Lilly has one of those blink-and-you-might-miss-it moments guess-starring in the episode "Kinetic" as a ladyfriend of one of the episode meanies.
I haven't used Choon to do anything useful, of course (even if you want to write down music in text form in Linux, there are much better options available). But I have used Choon to think of an absurd mental picture: an office full of programmers humming in harmony over the cubicle walls, perhaps to create the next version of TurboTax. I'm reminded of a scene in the educational film from the Pinky and the Brain episode "Your Friend Global Domination". Brain proposes a new language for the UN, Brainish, in which each speaker says either "pondering" or "yes" each time. By varying the tone and rhythm of their one-word statements, they can have a conversation about several topics simultaneously. I say Kupo! to that.Its special features are:
- Output is in the form of music - a wav file in the reference interpreter
- There are no variables or alterable storage as such
- It is Turing complete
Choon's output is music - you can listen to it. And Choon gets away without having any conventional variable storage by being able to access any note that has been played on its output. One feature of musical performance is that once you have played a note then that's it, it's gone, you can't change it. And it's the same in Choon. Every value is a musical note, and every time a value is encountered in a Choon program it is played immediately on the output.
Unrelated observations from killing time by watching old Smallville shows in syndication: 1) crazy Joe Davola is one of the producers, 2) Evangelline Lilly has one of those blink-and-you-might-miss-it moments guess-starring in the episode "Kinetic" as a ladyfriend of one of the episode meanies.
Wednesday, August 30, 2006
the Java closures that aren't
I admit to not reading the much-blogged closures proposal all the way through for the simple reason that I use Java version 1.4.2 at work (frankly, I have little to no say in the matter). I'm still waiting to throw out xdoclet for language-level annotations.
Nevertheless, I'm still glad to read Java Closures? Or just functors? Or just confusion? . Antonio does a great jorb defining real closures and functors, and thereby skewering the value of the proposed Java "closures". I especially appreciate this because I am consistently annoyed whenever people refer to a mere anonymous code block as a closure. Back when I used Perl more, I remember understanding code blocks (and references to code blocks) just fine, but having trouble understanding closures. I suppose it's a fine line, since languages with anonymous code blocks probably have lexical context and allow the code access to it, but try to answer the question "can someone create a full closure in Python?" and see how complicated the difference can be.
I didn't know about C++ functors until now. Of course, the term functor also represents a different technique in ML languages...*sob*
Nevertheless, I'm still glad to read Java Closures? Or just functors? Or just confusion? . Antonio does a great jorb defining real closures and functors, and thereby skewering the value of the proposed Java "closures". I especially appreciate this because I am consistently annoyed whenever people refer to a mere anonymous code block as a closure. Back when I used Perl more, I remember understanding code blocks (and references to code blocks) just fine, but having trouble understanding closures. I suppose it's a fine line, since languages with anonymous code blocks probably have lexical context and allow the code access to it, but try to answer the question "can someone create a full closure in Python?" and see how complicated the difference can be.
I didn't know about C++ functors until now. Of course, the term functor also represents a different technique in ML languages...*sob*
Tuesday, August 29, 2006
is haskell hot or not?
So, Haskell is one of those languages that I keep hearing great things about, but I'm still not convinced enough to take a long, serious look at it. A use.perl.org journal entry by Ziggy makes Haskell sure smell like nirvana. Then I see something like Algebraic Topology in Haskell over at dzone.com, and Damian Conway's turn of phrase from another context, "brain-meltingly complicated", comes to mind. Maybe the moral here is that once you adjust to monads and lazy evaluation and other unique features, you can use Haskell to manage any level of complexity you wish--there is no artificial limit on expressiveness. But I'm only speculating. The usual caveat applies: if you write your software too cleverly, you just might have to maintain it for life. Don't forget another factor too: a powerfully expressive language without the particular libraries you need simply isn't as practically useful as a lesser language with those libraries. On a common VM platform, any language can use any library, so this is admittedly becoming less of a concern.
Ziggy's post is really about a perceived (I don't believe that the majority of developers out there truly care at this point) mainstream rise of functional programming. He (she?) links to Joel on Software's Can Your Programming Language Do This? as an example, which by the way is a brilliantly concise but easily understood explanation of how convenient some functional programming features can be. I must say that I would prefer Ruby versions of his code snippets. Ziggy also links to Kingdom of Nouns, which I've commented on before. I wonder if the people who use Ruby as a poster child of not being a kingdom of nouns are self-aware enough to notice that everything in Ruby is a noun (object)?
Bonus observation: Adam Bien's Weblog says that you shouldn't compare Javascript/Ruby to Java. Why? Because as I said in "clash of programming language civilizations", the values are different.
Ziggy's post is really about a perceived (I don't believe that the majority of developers out there truly care at this point) mainstream rise of functional programming. He (she?) links to Joel on Software's Can Your Programming Language Do This? as an example, which by the way is a brilliantly concise but easily understood explanation of how convenient some functional programming features can be. I must say that I would prefer Ruby versions of his code snippets. Ziggy also links to Kingdom of Nouns, which I've commented on before. I wonder if the people who use Ruby as a poster child of not being a kingdom of nouns are self-aware enough to notice that everything in Ruby is a noun (object)?
Bonus observation: Adam Bien's Weblog says that you shouldn't compare Javascript/Ruby to Java. Why? Because as I said in "clash of programming language civilizations", the values are different.
Tuesday, July 25, 2006
a lisp evangelist who actually makes sense
In my continuing quest to learn and experiment with F#/OCaml, I decided that I should get to know tried-and-true functional programming techniques in a functional programming mindset. Otherwise, I would end up writing the same code but in different syntax, mmm'kay? I remember reading Perl gurus mocking people who programmed "C in Perl", and more recently I remember a case of a Python guru complaining about some "Java in Python". I've certainly run across OCaml examples that were clearly imperative-style, not that there's anything wrong with that.
Anyway, in my attempt to figure out how to do "functional design" I came up with this link. I highly recommend it. The writer tries to get across exactly what makes Lisp special and, as he describes, enlightening. But he does it by starting with concepts that are understood by his audience, much like ocaml-tutorial. He starts with XML, an extendable tree data format. From there he goes to Ant, in which XML is both data and code. As he says, the jungle of parantheses in Lisp is just a more concise way than XML of expressing a collection of nested elements, so it's not that bad to convert an XML document to a Lisp s-expression. Then he points out that Lisp can assign identifiers, known as symbols, to lists. Lisp functions are created just by passing a couple lists representing parameters and code to a built-in function that creates a function from the lists. Finally, lists are evaluated as functions, in which the first element is the function name and the remaining elements are arguments, unless the list is marked as being data with a simple ' mark in front. With these pieces, he can explain that a Lisp macro is just a special function that takes a data list and returns a (nested) list that will be evaluated as code. Unlike C with its preprocessor or Java using Ant, Lisp needs no templating language because it is its own!
Moreover, defining new macros is painless enough that Lisp can be extended at will...in fact, one way of attacking a problem is to define some macros in what amounts to a "domain-specific language" that is in turn defined in terms of Lisp. Much different from what I've read about caml4p. Then again, I know that I have only a superficial understanding.
There's another article at the same site that explains the benefits of lazy evaluation and continuations. But learning Haskell is not something I wish to do right now...
Anyway, in my attempt to figure out how to do "functional design" I came up with this link. I highly recommend it. The writer tries to get across exactly what makes Lisp special and, as he describes, enlightening. But he does it by starting with concepts that are understood by his audience, much like ocaml-tutorial. He starts with XML, an extendable tree data format. From there he goes to Ant, in which XML is both data and code. As he says, the jungle of parantheses in Lisp is just a more concise way than XML of expressing a collection of nested elements, so it's not that bad to convert an XML document to a Lisp s-expression. Then he points out that Lisp can assign identifiers, known as symbols, to lists. Lisp functions are created just by passing a couple lists representing parameters and code to a built-in function that creates a function from the lists. Finally, lists are evaluated as functions, in which the first element is the function name and the remaining elements are arguments, unless the list is marked as being data with a simple ' mark in front. With these pieces, he can explain that a Lisp macro is just a special function that takes a data list and returns a (nested) list that will be evaluated as code. Unlike C with its preprocessor or Java using Ant, Lisp needs no templating language because it is its own!
Moreover, defining new macros is painless enough that Lisp can be extended at will...in fact, one way of attacking a problem is to define some macros in what amounts to a "domain-specific language" that is in turn defined in terms of Lisp. Much different from what I've read about caml4p. Then again, I know that I have only a superficial understanding.
There's another article at the same site that explains the benefits of lazy evaluation and continuations. But learning Haskell is not something I wish to do right now...
Subscribe to:
Posts (Atom)