|
2013-05-15 Why I've so far been neglecting functional programming languagesFunctional programming languages are in many ways the latest hotness and so for years I've been making off and on runs at things like yet another explanation of monads (which I think I sort of understand by now) and similar topics. Despite this, so far I've been almost completely uninterested in actually trying to write a functional program or exploring a FP language. The big problem for me is that as far as I can tell, the kind of programs I usually work with are exactly the kind of programs that functional programming is stereotypically a bad fit with. The stereotype I've absorbed is that functional programming is quite a good fit for computation but not a good fit for IO, because IO intrinsically has side effects. Unfortunately most of what I write is all about IO and has little or no computation. Bashing a squarish peg into a roundish hole is unlikely to tell me anything particularly meaningful about nice the language is to work in; what I really need is a roundish peg, a computational problem, and those are relatively scarce around here. (It's possible that I'm not looking hard enough. For example, I do periodically want to do things like log analysis or event reassembly, where the original data could just as well be a predefined data structure in the program instead of processed from logfiles on disk. I suspect that a functional language would handle these fine, maybe better than ad-hoc hackery in awk, Python, or whatever. If I was really crazy I would try rewriting the logic in our ZFS spares handling system in an FP language to see if it got clearer; it's fundamentally a series of transformations of a tree and then some analysis of the result. The result might even be more testable.) (One comment.)
WhyNotFunctional written at 00:56:36; Add Comment
2013-05-13 My language irritations with Go (so far) and why I'm wrong about themThe great thing about an evolving language is that if you're slow enough about writing up your irritations with it, some of them can wind up fixed (or part fixed). So this list is somewhat shorter than it was when I originally wrote my first Go program, and none of the irritations are major. Also, I will reluctantly concede that Go has good engineering reasons for all of them. My largest single irritation is that
Instead you have to invent a boolean loop condition. I understand why Go
does this; it enables you to exit early out of a The issue that got partially fixed is Go's return requirements. When I wrote the original version
of my program the natural form of one function was a big switch with
a number of specific cases and then a You can make an argument that the original and current state of affairs
are good software engineering. If the compiler did true reachability
analysis it'd increase the number of cases where an innocent looking
change to some part of the code would suddenly make the My final issue is my perennial one of being unable to cleanly cancel IO being done by goroutines, breaking them out of things so that they can see a death signal from outside. You can argue that this is a bug in the runtime, but the problem with this is that everything that calls an IO operation then needs to be aware of this particular error case (and catch it, and propagate it up the call stack in whatever way is appropriate). A good start to making it a bug in the runtime would be for the runtime to define a specific error for 'IO attempted on closed connection' and for absolutely everything to use it. (As it stands, the Again this is a software engineering tradeoff. Both the semantics and the runtime implementation of goroutines are undoubtedly vastly simplified because you don't have to worry about being able to signal or cancel a goroutine from outside itself. Outside of the program exiting, all of the interaction that a goroutine has with the outside world are initiated by itself, on its own terms. This makes it much easier to reason about the effects of a goroutine, especially if it's careful not to use global state.
2013-04-15 Go's friction points for me (and a comparison to Python)A commentator on my entry on Python's data structures problem asked in part:
This brings up the complex issue of my views on Go. Part of the issue is that Go has a bunch of friction points right now. Some of them are intrinsic in the language and some of them are simply artifacts of the current situation and will hopefully change. (I wrote more about where I think Go fits into my programming back in GoInterest.) In general I don't think that Go will ever be as fast to program in as Python is (in the sense of how long it takes me to write a program, not in how fast it runs). Go goes to a lot of work to reduce the amount of bureaucracy involved through various features, but Python is simply at a higher level in terms of eliminating make-work and as a result it's significantly more flexible and adaptable. The tradeoffs involved are sensible for both languages and their goals; as discussed Go has a strong emphasis on large scale software engineering and Python doesn't. (To put it one way, Go is a great language for large scale software projects but I almost never write those. As a sysadmin I'm generally a small scale programmer.) I'm going to split this into current and intrinsic friction points, then do this in point form to keep the size of this entry from exploding. First, the current friction points:
(There are also pragmatic issues with using Go in production.) I thought that I had several intrinsic language issues but at this point all I can think of is the general extra annoyance of explicit error handling as opposed to Python's tacit exceptions. I understand why Go makes the choice it does but Python's exception-based approach is just plain convenient for quick coding and it means that you can write much less code (you can aggregate error checks and even skip writing explicit ones and your program will still abort on errors). (I consider things like Go type assertions to be part of the general price paid for static typing. I can't really describe static typing as a friction point, although to be honest it sort of is.) Also, as I've written before I maintain that Go's
obsessive focus on goroutines with basically no support for (If I use Go more I may find some additional irritations. Python is a relatively featureful language as compared to Go, so I may find myself missing things like function decorators at some point.)
2013-04-03 How to make sysadmins unhappy with your project's downloads
Let me expand on this a bit. First, I'll give a pass to everyone who has access-restricted downloads; there is no good way to make them easily fetched. This is for everyone else, all of the various projects that have public downloads. Here is the thing: sysadmins are not necessarily browsing your website
on the machine where they actually want the source code. In fact it's
almost certain that they aren't, since very few sysadmins run Firefox or
Chrome on their servers. What sysadmins want to do is use 'Copy Link
Location' on the (nominal) URL of your project's distribution tarball,
open a connection to the server, type ' There are at least two ways that this goes wrong. Sadly I am going to have to pick on the Django web framework for the first one, because it inspired my tweet. The download URL for Django 1.5.1 is:
If you feed this URL to The fix for this is straightforward: your download URL should have
a last component that is the name of the distribution tarball or
applicable file. Then (Github does a variant of this. The stated URLs of a zipfile of
a repo are things like <user>/<project>/archive/master.zip, but
the fetched file is supposed to be called <project>-master.zip.
Browsers that pay attention to the HTTP The other really bad thing you can do is what Sourceforge at least used
to do. The nominal 'download' links on Sourceforge projects didn't go
directly to the files (despite appearing as if they did); instead they
went to an interstitial HTML page that told you about mirrors and and
automatically started a download (I assume through the use of a HTML
' (5 comments.)
WgetableDownloads written at 00:28:48; Add Comment
2013-03-25 My (current) view of using branches in VCSesIn a comment on this entry, Aristotle Pagaltzis asked:
The simple answer is that my favorite way of changing branches is with
(Some people will say that you should keep even experimental stuff that didn't work out in your VCS in case you ever want to go back to it later. This may work for them but it doesn't work for me; I want my VCS to be neater than that.) But even without that I think (And disk space is generally cheap unless you're dealing with huge repos. The two largest repos I have handy are Mozilla and the Linux kernel; Mozilla is 2 GB and Linux is 1.2 GB. That's not going to break the bank on modern machines.) I understand why VCSes have branch-switching commands (they can't not have them, to put it one way) and the benefits of having multiple branches in the same repo (including things like being able to do easy diffs between branches). But it just doesn't fit into the way that I prefer to interact with VCSes and I like to keep my life simple. (4 comments.)
MyVCSBranchingView written at 01:20:58; Add Comment
2013-03-18 The wrong way for a framework to lay out projects
I'm sad to say that Django 1.4 is a great illustration of two bad things. First it is a great illustration of how not to lay out a project hierarchy and second it is a great illustration of how not to do a layout transition. Up until Django 1.4, the more or less canonical source layout of a Django project looked something like this:
The
The problem with this layout is that it breaks the first rule of sane
code layout: everything goes in a single directory hierarchy that
is your VCS repo. Modern VCSes manage a directory hierarchy, so you
really want to give them one. The Django 1.4 layout requires you to
invent a container directory purely so that you can put The other problem is transitioning an existing project that has, of
course, set itself up with the (Django people will say that Django is forced to do this because of
Python module handling issues. My view is that it is a mistake to make
things into modules in the first place when they are in fact not, and
2013-03-03 Why a netcat-like program is a good test of a languageWhen I talked about my first Go experience, I mentioned in passing that a netcat-like program is actually not a bad test program for a language (or for certain sorts of libraries in, eg C). Today I feel like explaining that. To start with, it's not an empty and artificial challenge; a netcat-like
program does something meaningful and practical (although it may not
be necessary if you already have netcat). The problem itself touches
many levels of a language and its library, since it has to interact with
standard input and output, deal with command line arguments, look up
hostnames and ports, make network connections and talk over them, and
deal with buffering and byte input and output. It also involves some
level of network concurrency, either through real concurrency (as in
Go) or through the equivalent with (In a low-level language like C you'll also wind up exploring things
like memory allocation and any safe buffer handling libraries that are
available. If you're working with Of course there are many aspects to a language and its libraries beyond relatively low level networking, so this problem doesn't come anywhere near to exploring all of a language and its libraries. Still, I've found that it covers a lot of ground that's interesting to me personally and the whole experience is a good way of seeing what the language feels like. Some people will want to write HTTP-based test programs instead because that's more directly relevant to them. I'm the kind of cynical person who wants to see the low-level plumbing in action too, partly because I think it's more revealing of the language's core attitudes. Since the web is so pervasive and important, my feeling is that everyone doing a new language environment is going to make sure they have good HTTP support (assuming they care about such usability at all). And if a language doesn't have either high-level HTTP support or good low-level networking support, well, that tells me a lot about its priorities.
Go: when I'd extend an interface versus making a new oneOne of the reddit suggestions in response to my entry on using
type assertions to reach through interfaces
noted
that you could embed one interface inside another one, effectively
extending the interface that you embed, so my
When I saw this my instinctive reaction was that this was wrong for my situation; since then I've spent some time thinking about why I feel that way. My conclusion is that I think I have good reasons but I may be wrong. Simplifying, the dividing point for me is whether all of the values I'm
dealing with would be instances of the new interface, for example if
I was writing code that only dealt with TCP and Unix stream sockets.
In that situation my life would be simpler if I immediately converted
the But if not all of the values I'm dealing with are convertible and if
I'm only doing the conversion in one spot (and only once), extending
I'd feel different if I was passing the converted values around between
functions or storing them in something. The issue here is that such
functions don't really want to accept anything that simply has a
The more I think about it the less I'm sure what proper Go style
should be here, and I have to admit that part of my feelings against
2013-02-21 Go: using type assertions to safely reach through interface typesTo start with, suppose that you have a Go
(In Go's software engineering view of the world this is a sensible
choice. So sometimes If you're a certain sort of beginning Go programmer coming from Python, you grind your teeth in
irritation, look up just what concrete types support
(Then this code doesn't compile under Go 1.0 because What this code is doing in its brute force way is changing the type of
(I am mangling some Go details here in the interests of nominal clarity.) The experienced Go programmers in the audience are shaking their heads
sadly right now, because there is a more general and typesafe way to do
this. We just need to say what we actually mean. First we need a type
that will let us call
(It's important to get the argument and return types exactly right even if you're going to ignore the return value.) Now we need to coerce
(We can't just call This is both typesafe and general. Any (I actually like this typesafe conversion and method access better than the Python equivalent because it feels less hacky and more a direct expression of what I want.) I think that it follows that any type switch code of the first form, one where you just call the same routine (or a few routines) on the new types, is a danger sign of doing things the wrong way. You probably want to use interface type conversion instead. (Had I read the right bit of Effective Go carefully I might have seen this right away, but Effective Go doesn't quite address this directly. All of this is probably obvious to experienced Go programmers.) Update: there are several good ideas and improvements (and things I didn't know or realize) in the the golang reddit comments on this entry.
Some notes on my first experience with GoI've finally wound up writing my first Go program. The program is a Go version of what seems to have turned into my standard language test program, namely a netcat-like program that takes standard input, sends it off to somewhere over the network, and writes to standard out what it gets back from the network. Partly because Go made it easy and partly due to an excess of new thing enthusiasm the program grew far beyond my initial basic specifications. (I'm somewhat bemused but a netcat-like program really has become a standard program I write in new languages and to try out things like new buffering libraries. It's actually not a bad test.) On the whole the experience was quite pleasant. The specific need I
had is something I normally would have handled with a Python program
and writing my Go program was not particularly much more work and
bookkeeping than the Python equivalent would have been (it took much
longer to write because I was semi-learning Go as I went and I already
know Python). The code has reasonably few variable declarations and most
of them are non-annoying; Go's One important thing I wish I'd know at the start is that you should ignore most everything the Go documentation overview pages tells you about what to read. Effective Go is in practice the quick guide to Go for C programmers, or at least for C programmers who have some general idea about Go to start with, and is the closest thing Go has to Python's excellent tutorial. The language reference is overly detailed and too hard to read for learning and the interactivity of the beginning tutorial makes it completely unsuitable for quick starts. One of the reasons that I got as far as I did as fast as I did is that
Go's networking library has a relatively high-level view of the world.
There is no Python equivalent of Go's My code wound up using goroutines and channels, although in a relatively basic way. Designing program flow in terms of channels definitely took several attempts before I had everything sorted out cleanly; earlier versions of the code had all sorts of oddities before I sorted out exactly what I wanted and how to express that in channel data flows. My broad takeaway from this experience is that it's very important to think carefully about what you want to do before you start eagerly designing a complex network of channels and goroutines. It was easy for me to get distracted by the latter and miss an obvious, relatively simple solution that was under my nose. My feelings about channels and goroutines are mixed. On the one hand I think that using them simplified the logic of my code (and made it much easier to support TLS), even if it took a while to sort out that logic. On the other hand having to use goroutines is responsible for a serious wart in one aspect of the program, a wart I see no way around; the wart arises because there's no way for outside code to force a goroutine blocked in IO to gracefully abort that IO (this is a fundamental issue with channels). This is rambling long enough as it is, so I think that I will save my language disagreements for another day. Well, except to say that I think that the standard Go package for parsing arguments and argument flags handles command line options utterly the wrong way and I need to get a real argument parsing package before I write another Go command. (Go's standard
|
These are my WanderingThoughts GettingAround This is part of CSpace, and is written by ChrisSiebenmann. * * * Atom feeds are available; see the bottom of most pages. Categories: links, linux, programming, python, snark, solaris, spam, sysadmin, tech, unix, web |