Disagree with the conclusion, the answer is much simpler. As a rule, if the project isn’t documented just assume it probably isn’t suitable for public use and certainly isn’t suitable for production use.
Github exists to share so by all means put code in any form up for others, just don’t put it undocumented into a package manager like Hackage or PyPi where it can subtly be pulled in. That is the real harm to communities.
My question is though, what do you hope to gain by sharing. Many people actually post these projects with the intent that people will use them, but then offer little or no documentation. Even many widely used projects have scant documentation (yes, few have none at all). In fact, the basis for the article came out of my own frustrations trying to use a number of open source project recently in preparation for a conference presentation - many of which were widely used (and many users of which shared my frustrations).
I keep virtually all of my code on GitHub, that way, I have a backup. What few non-open source things I do are in private repositories.
Or if I have multiple computers, it lets me share code between them without having to do some kind of obnoxious syncing.
A ton of people have dotfiles repos. No, my dotfiles are not production ready. No, I’m not going to mark my dotfiles as not ready for production.
Right. I think a lot of people do. What I suggested though is that you indicate with some sort of disclaimer that this is personal or experimental and you do not intend to support, maintain or document it. Makes it quick and easy for you and quick and easy for a consumer to make an informed choice about using it.
This is always true with open source, no matter what. We like to pretend that it’s not true, but at the end of the day:
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
There are projects that I’ve been the maintainer of with tens of thousands of users, and then life happened.
There are all kinds of other things that point toward this, though: only one contributor, very few commits, no documentation. That says it way more effectively than any kind of disclaimer I could make.
Yeah. We’ll know software engineering has made progress if we ever get to a point where we can safely omit that wording. It’s hard to imagine, right now, even with formal verification.
It’s hard to know or predict what someone will do with a piece of software. There are a finite number of requirements for a screw you buy at the hardware store. If your shed collapses because you didn’t use enough screws, that’s obviously your fault. If your website collapses because you used the wrong template engine, well how could you have known that? Obviously time to blame the author.
There are plenty of examples where this simply isn’t true (in fact, the author clearly intended it to be shared, but didn’t bother doing any real documentation). Thus the impetus for the article.
(in fact, the author clearly intended it to be shared, but didn’t bother doing any real documentation)
This is saying that it’s intended to be shared. But in the end, it’s still not offered with any kind of warranty; I can release a library with no documentation if I don’t want to write documentation.
Documentation decreases the barrier to entry to using a particular piece of software. Zero documentation does not necessarily imply an infinitely high barrier to entry. If someone is motivated enough, the lack of documentation may not prevent them from reaping the benefits of the code that was shared.
I get that the world would be a much nicer place if we didn’t share things that were significantly lacking in quality. We should definitely continue to advocate in favor of documenting your code, even if you don’t share it. But it’s the wrong thing to should-people-to-death for. The better thing to optimize for, IMO, is to teach others how to identify whether a project is worth using or not.
Because other people can reference it if their time is not valuable and they’re willing to put the time in to read the source. Code gets open sourced for a lot of reasons, and a lot of them are not necessarily for to make something that’s immediately usable in a commercial setting. How people donate their time is really not something you can expect to really control.
Thus the above advice: If it’s not documented and you’re on the clock, assume the library doesn’t exist honestly.
There are plenty of employers who look at your github activity as a quick gauge on your code/activity level outside of work or classes. Not necessarily a fan of the practice, but it is a real reason people put up code that’s not for widespread consumption.
Many users shared your frustrations, but they’re still users. Their frustrations with the project must be less than whatever frustrations drove them to use someone’s undocumented code. If enough people find this code useful, maybe they’ll consider contributing documentation back to the code base as they figure it out. If the author sees this, they may realize that if people find the undocumented draft project useful, that maybe it’s worth some effort to improve it. Or the author doesn’t care, someone forks the project, and it takes off.
There are many paths to useful open-source projects, and they don’t all require the author to spend an inordinate amount of time documenting every feature for a project nobody may ever see. The onus on deciding how to put together your project is still on you, not the authors of every piece of open-source code that might be relevant to your project.
You think people publishing code are doing it for you, and want to chastise them for not bringing the quality to your standard?
I think it’s much more sensible to simply assume that they’re not doing it for you, but for some other reason. That is to say that I don’t think people post these projects with the intent that other people will use them, but for some other reason. Some do it because it is a convenient backup, and others because it’s the minimum needed to get a contribution, but I don’t know anyone who does it for other people.
And yet: I do want projects to have better documentation. I think a documentation standard is more valuable than a coding standard: We are writing for humans; the computer does what we say, but we write to express what we mean so that human beings can fix our mistakes in stating it correctly. To this end, I recommend that programmers write documentation first, and then implement the documentation, and I consider a programmer who cannot document his software to not be a very good programmer. I just don’t think this blog posting is how we get there.
Has anybody here used this for asp.net projects on linux? We have to use c# with asp.net in one of my classes and I tried doing one of the assignments in vim with the omnisharp plugin and it did not go very well..
The omnicompletion was fine, compilation worked great, the only problem were the myriad configuration files that visual studio generally manages made it impossible for me to make proper webforms, as soon as I’d try to hook up an event, I’d get runtime errors.
I have done ASP.NET MVC apps on linux, and vim works ok. Visual Studio/Visual Studio Code still have better autocomplete though.
The omnisharp-roslyn stuff technically uses Roslyn – the same thing we use in VS to power the C# language service, but the devil is in the details.
We’re still working on generating a completely platform agnostic Roslyn abstraction that will let consumers everywhere “plug in” to the language service at various points.
When you become too well known, or too widely used and too successful (and certainly being adopted by Microsoft means such a thing), suddenly you can’t change anything anymore. You get caught and spend ages talking about things that have nothing to do with the research side of things.
Boy isn’t that true. At the same time, in my experience ‘research’ mostly means figuring out what you can do. Note that that’s not what you should do or what you want to do, but what you can do. Productized languages, on the other hand, are mostly about taking well understood problems and trying to produce solutions. It’s an interesting dynamic and I think different people will fall on different sides of it. As for me, while coming out of grad school I would have said I would want to work on the research side, after being on the product side I can’t help that feel that most research is simply about producing abandonware that may eventually end up inspiring someone’s real solution. Personally, I’d rather be at the end of the pipeline, interacting with users and solving their problems.
A lot of the problems in the cache misses section are things that I’d like to address in C# 7. The current proposal for ref returns/locals would help here.
It seems like many of the issues in this article and those like it can be attributed to the absurdly low barrier to entry for software companies. If you have no money, no likely revenue, and nothing holding you accountable, are you a company or a club? Bio-tech startups certainly don’t work this way.
Tangentially related: I don’t remember ever hearing anyone say “How can we get more people into chemical engineering?” or seen any Learn-to-play-with-deadly-chemicals-in-12-weeks “engineering” courses.
The article’s critique was anchored specifically on the comments of the founders of Paypal, Facebook and 42Floors. “No money, no likely revenue, and nothing holding you accountable” doesn’t really seem to apply.
Bio-tech startups would seem to have diversity problems that mirror those of software startups fairly closely.
“You can’t underdress to a Bio-tech interview” He was failing the come-over-for-dungeons-and-dragons test and he didn’t even know it…
I know of bio-tech startups that behave very similarly to this. Perhaps not in the clubby, hipster way, but in a manner that suggests a similar lack of professionalism in social aspects.
I don’t remember ever hearing anyone say
There are certainly efforts in other fields to encourage more people to get into them.
But, and maybe this is just personal bias, chemical engineering does not underlie so much of modern socio/political/economic power in the way that software does. Software is eating the world, and without some kind of base literacy, it’s increasingly hard to understand what’s going on around us. That’s why I think more people should have at least a tiny understanding of how computing works.
I would maybe argue that this is personal bias. Understanding chemistry is the basis of petroleum engineering, pharmaceuticals, materials science, and a bunch of other really important stuff (generating and storing electrical energy efficiently, fertilizers/pesticides, etc.). Between them those things underlie a vastly larger fraction of socio/political/economic power in the world than software.
I think it’s easy to get an inflated idea of the importance of something (e.g. software) when you live and breathe it every day.
If I had to guess why there’s such an outsize effort to get people into software I would probably say it’s just because there happens to be a labor shortage at the moment, but I don’t really know ¯_(ツ)_/¯.
Replying to both you and your sibling, computing is what ends up controlling all those important things, however. And communication is a greater power than any particular physical good, and that’s all computerized at this point.
I do think all fields are important, regardless.
Supporting @steveklabnik’s point, from the original Software is Eating the World essay:
Oil and gas companies were early innovators in supercomputing and data visualization and analysis, which are crucial to today’s oil and gas exploration efforts. Agriculture is increasingly powered by software as well, including satellite analysis of soils linked to per-acre seed selection software algorithms
Fair point, although you can’t communicate on any modern medium without oil and electricity to power it (nor can you even make a computer!); there’s sort of a chicken and egg thing here :P
I guess I don’t really see the argument that computing is a more reasonable thing for everyone to understand the basics of than chemistry or physics or biology or what have you; all of it is important and runs the the world in some way. Maybe we should encourage people to learn a bit of everything :)
you can’t communicate on any modern medium without oil and electricity to power it
This is absolutely true, and something I worry about way more than I should, probably.
Maybe we should encourage people to learn a bit of everything :)
Yes, very much this. This over-focus on STEM is incredibly harmful :(
From here it looks like most jobs over the next century will require skills we currently think of as software skills. In the same way that most jobs today require some kind of “functional computer literacy”, and most jobs last century required ordinary literacy. The skills of programming seem generally applicable, in a way that something like materials science (while fascinating, and underlying lots of recent engineering advances) isn’t. Will knowing chemistry/physics/biology make you a better accountant/architect/artist? Maybe, but the connection seems more direct and obvious for computing.
I’d tend to agree, which is what I posited in my OP: the push for people to learn computing is more about the labor market than anything else.
I think that’s totally personal bias. Oil has more power than computing could ever dream of and no one is saying “teach all our kids petroleum engineering.”
I think that the importance of software lies on the fact that it works as a tool to enhance people’s capabilities. While other fields may be directly involved in the production of good and services that are fundamental to support our modern lifestyle, software not only has an impact on these fields but in almost everything else we do, be it big or small. Because of this, its reach is, at least, much larger than any other field I know of.
For those not wanting to watch 6 minutes of video, the summary is:
Haskell has traditionally been safe but also useless, meaning that it’s free of side-effects (and what’s the point of a computer program that has no side effects?). He contrasts this with C, Java, C# which are unsafe but useful and points out that all languages are developing in the direction of safe and useful. For C/Java/C# this means going from unsafe to safe, and for Haskell it means going from useless to useful. To do this for Haskell, they’ve figured out how to keep side effects separate from pure code, and this concept has been slowly leaking back into C#.
and what’s the point of a computer program that has no side effects?
A side-effect is a function which does something other than produce a value. We don’t need those to write programs; Haskell is the perfect example of treating IO as values.
The act of producing a value is a side effect. If you print it to a screen, it’s a side effect. If you set the exit code of your process, that’s a side effect. If you want to do anything like communicate with a database or a service or a keyboard, those are all side effects.
Even non-termination is a side-effect (one which happens to be uncontrolled in Haskell).
The act of producing a value is a side effect.
What does that mean?
I’ve seen some people say similar things but their definition of a side-effect is “something does something” which is next to useless and not what side-effect actually means!
I think the following sentences explained it very well.
To actually produce a value using a program running on a computer it must perform a side effect. This is the standard definition in the literature, including Peyton-Jones’s.
Edit: I think I see how this is confusing. Technically, any observable effect of running a program is a side effect. Modifying the exit code of a process is observable and is technically a side effect.
However, this tends not to be a definition of super-practical use. In context, the term “no side effects” is often used as more of “it doesn’t really touch state that matters.” This is also the way monad is often used – people will say something is a monad, when it has the right type, but actually doesn’t strictly follow the category rules.
The point I was making was really that you were nitpicking unproductively. Serious language designers should recognize that the goal in language design is to actually write programs, not debate grammatical points.
I don’t think I’m nitpicking, it’s an important distinction to make and people often get it wrong. I don’t think it’s unproductive to point out the problem, especially since you’re now wondering about it.
To actually produce a value using a program running on a computer it must perform a side effect. This is the standard definition in the literature, including Peyton-Jones’s.
Here’s a screen shot of the awesome Functional Programming in Scala book. Doing something other than “returning a value” really is the formal definition! Pinky promises that I’m not making things up.
Serious language designers should recognize that the goal in language design is to actually write programs, not debate grammatical points.
I don’t know what this means, are you imagining a dichotomy between talking about what ‘side-effect’ means and enabling the writing of programs? What does it mean to be a serious language designer?
Purity is a bit up to the language to define, however. For instance, evaluation in Haskell can force thunks and cause the execution of other code to change observably. It’s simply a matter of Haskell preference to decide that evaluation time is “unobservable” from the point of view of the language semantics.
There still a super important distinction to be had around purity. It becomes the most clear when you have strong types and thus a consistent and total notion of canonical values. In that case, one poor image of “purity” is to say that the only value you get out of running a function is to receive the canonical value of its result. In a more mathematically rigorous sense you might write
The function f : A -> B is pure iff
const () . f == const ()
In other words, when I throw away the result of computing the function f using const () the result is somehow “equal” to const (). The exact choice of const () and the exact meaning of equality shift around, though, and provide slight variations on what purity means. For instance, we might replace const () with
trivial :: a -> ()
trivial a = a `seq` ()
which is a more restrictive form of “purity” since non-termination is now a side-effect.
How is it a preference for Haskell to say that evaluation time is unobservable? If Haskell allowed functions to observe time then those terms would not be referentially transparent! It’s not about what a language is “allowed” to observe.
Haskell works under the definition that bottom is a valid value and seq is not referentially transparent. If you change the definition of Haskell terms, you could say that bottom is not a value and then you get to say that non-termination is a side-effect. I’m definitely with you on doing that!
No, of course. Haskell is internally consistent with its definition of pure (except where it isn’t, and those places are forbidden). I’m just relating that the definition of side effect is often a little bit fuzzy at least. It’s a good argument to have as to what the tradeoffs of stricter and stricter definition of purity are.
I’d love to have non-termination as an effect, but I’m also perfectly happy to admit that it’s a tradeoff.
So under this definition, what isn’t a side effect? I don’t disagree that most of the things you mentioned are side-effects but if we extend this notion such that even producing any value is a side-effect then this is just a truism since every conceivable computation is effectful. It’s more interesting to study the topic under the constrained definition of observable vs unobservable effects.
No, once you accept the definition that everything is a side effect, it lets you focus on adding language support for controlling the side effects that matter.
Writing
x = 1 y = 2 x = 1
Is side-effectful according to Haskell definitions (you modified x), but it’s also completely unimportant. You haven’t gained anything from pointing that out. Talking about side-effects is only useful in a highly contextual discussion about making it easier to perform some specific task in a programming language.
You do gain things from pointing it out, though. Huge things!
By pointing out something is a side-effect, you’re also pointing out that you’ve lost referential transparency. By pointing out that you’ve lost referential transparency, you’re also pointing out that you’ve lost the substitutional model of programs. By pointing out you’ve lost the substitutional model of programs, you’re also pointing out that you’ve lost equational reasoning.
And I really don’t want to lose equational reasoning. I do functional programming because I highly value treating my programs as sets of equations. It allows me to treat types as theorems, allows abstraction without implications and is just an extremely simple form of formal reasoning which people can do in their heads or on paper!
When I was writing C and IA-32 assembler in kernel mode I didn’t care that I didn’t have equational reasoning and I didn’t want equational reasoning. I was altering state by writing a program that altered state in exactly the way I wanted it to.
You’re describing a very specific way of writing a program. What you don’t seem to accept is that it is not the only way to write programs, or sometimes even the best way to write programs. Sometimes those two ways of programming are even two parts of the same program. Maybe I want referential transparency sometimes, and not others. It’s the job of the language to help me perform the task I’m working on in the best way possible in that context.
That seems a little like an appeal to moderation, can you clear it up for me and give an explicit reason to not want a substitution model for your programs?
I know I’d definitely take referential transparency when describing a kernel, if I could get it. It would absolutely give me more confidence that I’m altering state in the exact way I’d want to. I may not be able to achieve it, but that doesn’t mean I wouldn’t want to!
I accept that we can’t have referential transparency with assembly. That code doesn’t make me want to give it up, though, it makes me want to get to a place where we can do what assembly can while maintaining referential transparency!
Can we? Who knows? I just know I’m not satisfied…
Oh, I just realised that we could define this stuff inside of an referentially transparent EDSL and could probably do the same stuff. Almost like what Microsoft has been playing with.
what Microsoft has been playing with.
Hey, I never said that typing was inappropriate.
(Also, read the discussion on that paper. It’s quite funny – basically Andrew is trying to describe in the kindest words how crappy their dev experience was).
Great tl;dw (didn’t watch)
There was something that Simon Peyton Jones once said (though I’m having trouble finding the link) where he mentioned that you can parse the unofficial Haskell motto: “avoid success at all costs” in two ways. The first way, and probably the way that most people take it is “do everything you can to not be successful.” Haskellers sometimes joke that we’re starting to fail at that. But Simon mentions that you can also parse it in another way (my paraphrasing): “avoid doing unprincipled things just to become popular.” So it could be: “avoid: ‘success at all costs’.” And I think this video hints at that. Haskell started “safe but useless” and is moving carefully up the usefulness axis.
Reminds me of this quip: http://ro-che.info/ccc/17
I don’t really understand why we have to either be “for static types” or exclusively “for dynamic types.” Isn’t possible to be for neither and understand that they each have their own unique set of trade offs?
I think there’s a feeling that static types completely supersede dynamic types with such minimal side effects that there’s no conceivable reason to pick dynamic types should you have the option. These arguments usually proceed technically noting that statically typed languages can embed dynamically typed languages with no trouble while the opposite is not true. This seems to be a clear indication that static typed languages are “more powerful” than dynamic typed languages. Further, since this embedding proceeds via static typing formalism it’s easy to say that those who disagree simply have not learned sufficiently much to be familiar with this argument and would be immediately changed should they ever learn it. Finally, it’s sometimes the case that a person who’s been extensively exposed to dynamically typed languages will learn the static formalism to understand the “uni-typed argument” and then will end up feeling static types are superior thus forming an existence proof of this progression.
I think that’s a technical description of what happens sometimes from the statically typed languages camp. Note that it’s a bit fallacious in that it conflates “embedding” with “superiority” without really defining the latter. Oftentimes definitions of superiority are given but it’s unclear whether those notions still follow from “embeds” let alone whether everyone ever agrees about those definitions.
From the dynamically typed languages camp people tend to argue from proof of popularity and existence of solutions. It’s hard to understand why introducing more technology, its corresponding immediate mental overhead (again, static types embed dynamic types and thus, often, are additional formalism beyond dynamically typed languages), and the associated retraining costs will “improve” code which can and has already been written. It’s rare to find anyone who would argue that code written in a dynamically typed language cannot be more easily made to run than code written in a statically typed language (though both camps may implicitly assign different value judgements on this outcome).
As a final force, it’s often the case that additional formalization can be added “atop” a language. Some might even consider “unit testing” at large to be such a thing, although a more commonly acceptable example might be Valgrind. This extra formalization can be seen as either “checking programs” or “restricting the language definition” based on your point of view. It turns out that oftentimes people using dynamically typed languages will seek out these extra formalizations in order to provide faster feedback loops on the correctness, safety, or resource utilization of their programs. It also turns out that people using statically typed languages do the same (again, see Valgrind) although these tend to be characteristically different from the systems used for dynamically typed languages since statically typed languages already have higher levels of formalization.
Ultimately, all of these forces are at play and lead to a great deal of debate while the real value judgements at play are ignored. Greater formalization leads to faster response cycles on program creation (which is often considered a pro) but may do so using less information and thus be less informative themselves. Ultimately, this forms a UX problem: for different kinds of programming tasks do you want a programming interface which tells you quickly when you’ve made some class of errors or one that defers failure and allows you to determine more information about the runtime first?
A further concern is that systems which defer more errors for later stages today tend to be less capable of “completeness”. As an example, building a unit testing suite will help you to validate your program but due to its expense and nature it’s unlikely to ever build a unit testing suite which comprehensively confirms global properties of your program (such as static type safety). Dually, systems which respond more quickly tend to be less capable of “depth” as they must operate with less runtime information.
Both of these weaknesses are being addressed. “Incomplete” systems are growing more powerful and seeking out ways of examining whole ASTs for interesting properties (see: Typed Clojure or Dialyzer) while “shallow” systems are growing stronger formalisms for capturing higher information scenarios (see dependently typed languages and theorem provers).
The “embedding” property is an interesting one that everyone should be familiar with—and I think personally I agree with some of the static typing zealots who suggest that people who “do not understand static types” tend to be unfamiliar with it whether or not I agree that this unfamiliarity is damaging. However, instead of using it as a poor proxy for “superiority"—especially of any particular language over any other—it’s better to see it as evidence that all of these techniques are, in theory, composable.
Since we’re ultimately solving a UX problem which discerns between variables like “error detection turnout cycle time”, “richness of error information”, and “completeness of evidence of validity” we might prefer a system (or set of systems) which allow us to tune each of these things and use them as the situation calls for it. As far as I’m aware no such system exists, though GHC’s –fdefer-type-errors is a step in that direction as is Typed Clojure and Typescript.
Finally, there’s an open research question as to “ease of use” and “error risk”. It’s hard to answer questions directly such as “is it easier to learn a statically typed language or a dynamically typed one” as it’s impossible to (a) formulate what “easier to learn” means and (b), more powerfully, it’s impossible to establish that counterfactual without using a randomized study which is, today, infeasible.
There is a lot of evidence in process engineering that suggests that early error detection vastly improves total cost of creation (I wish I could remember the guy’s name who pioneered a lot of the observational research on this!). This seems to provide justification that statically typed languages can lead to much faster total development time. Unfortunately, this effect is often compared with startup times (which can be mitigated by an enormous variety of techniques including pure tool familiarity) and mischaracterized. This is sad because it’d be great to have real data about how different kinds of process testing (and I’ve outlined quite a variety above) actually do or do not improve various kinds of projects. Information like that would be instrumental to efforts to better solve the language UX problem outlined above.
Welcome to tribalism on the Web, I guess? People identify with their tools inappropriately and interpret good things said about alternatives as attacks on themselves.
Knowledge of the state of the art almost always means not finding uni-typed systems very interesting. At least for practical day-to-day work anyway. We’re talking about differences on the scale of arguing in favor of outhouses rather than indoor plumbing. You won’t get serious arguments for that from people with comprehensible value preferences.
I used to use Clojure (Python, Common Lisp), now use Haskell. I simply didn’t know any better despite thinking I knew what type systems were like due to exposure to other statically typed langs.
I was very wrong. And no, Scala and OCaml don’t hit the mark.
I’ve talked to people that have published on augmented uni-typed systems who still didn’t know much about what writing code in more advanced languages was like, so it’s not only industrial programmers that lack exposure.
Mine and other peoples' experiences are discussed here: http://bitemyapp.com/posts/2014-04-29-meditations-on-learning-haskell.html
Repeat: I used to be on the other side of these debates. Had tons of experience in Lisps, statically typed languages, FP, the works. I still didn’t know any better.
Knowledge of the state of the art almost always means not finding uni-typed systems very interesting. At least for practical day-to-day work anyway. We’re talking about differences on the scale of arguing in favor of outhouses rather than indoor plumbing. You won’t get serious arguments for that from people with comprehensible value preferences.
Well, that’s pretty condescending. Either I don’t understand functional programming or I don’t have “comprehensible value preferences.”
I know this may shock you, but I’m actually quite happy to program in either Haskell or Python. (And gasp, I like Go too! I know, crucify me already and get it over with.) It very much depends on what I’m doing. And if you can get off that high horse of yours, you might discover that there are a lot more people like me.
(Hint: Life is about trade offs. Sometimes an outhouse is exactly the thing you want because indoor plumbing isn’t feasible or is too costly. And you know what? There’s absolutely nothing wrong with that.)
We are already in a situation where programmers immediately dismiss Haskell with the quip, “I’m just not smart enough to grok it.” (Uttered from the mouths of programmers that I otherwise respect. But what do I know? I have incomprehensible value preferences!) If you’re going to play right into that, then you really have zero hope of motivating that sort of programmer to really dip their toes into a language like Haskell.
And if that’s the case, then at the end of the day, what is it that you hope to achieve by purposefully using language that encourages tribalism and snobbery?
It’s easy to say, “Well, once you know what I know, then you’ll see the light and all will be well.” It’s much harder to figure out a way to relate functional programming to those who haven’t been exposed to it and demonstrate how it can improve their lives. Feel free to guess at which approach I’ve found to be more effective in practice.
Repeat: I used to be on the other side of these debates.
Dammit! You’ve utterly and completely missed my point. This isn’t a debate. My comment didn’t say, “Well actually, dynamic typing is superior.” It said, “There are different trade-offs involved when using static typing and dynamic typing.” This implies that one could be a better a choice than the other depending on which trade offs you value.
I know this may shock you, but I’m actually quite happy to program in either Haskell or Python.
Not especially. I use Python too.
(And gasp, I like Go too! I know, crucify me already and get it over with.)
Are dramatic parentheticals necessary for your response to my comment?
(Hint: Life is about trade offs. Sometimes an outhouse is exactly the thing you want because indoor plumbing isn’t feasible or is too costly. And you know what? There’s absolutely nothing wrong with that.)
This is a false economy in this case. My mistake for resorting to the analogy.
If you’re going to play right into that, then you really have zero hope of motivating that sort of programmer to really dip their toes into a language like Haskell.
I’ve motivated my share programmers into learning Haskell and continue to do through education. I’ve only gotten guff from people with something to protect on an internet forum.
It’s much harder to figure out a way to relate functional programming to those who haven’t been exposed to it and demonstrate how it can improve their lives.
I don’t have this problem at all when I teach people Haskell. But they have to be ready to learn. If it’s about debating on an internet forum, then yeah, I’m wasting my time.
It’s not difficult to teach Haskell if you understand Haskell. Haskell isn’t the easiest language I’ve taught, but it’s far from the hardest.
Do you write software for a living? This stuff is a lot more impactful when you’re a professional software engineer who has to maintain systems over a period of time as opposed to writing code that works once and then is discarded.
Have you read the post I linked? The points about maintenance, refactoring, etc that I’m alluding to are a core part of the value proposition.
Do you write software for a living? This stuff is a lot more impactful when you’re a professional software engineer who has to maintain systems over a period of time as opposed to writing code that works once and then is discarded.
Way to be patronising, dude. Plenty of really smart serious professional people prefer to program in “uni-typed” systems and have created some pretty fabulous stuff with them. Can’t we all just enjoy our own preferences without denigrating each others?
Plenty of really smart serious professional people prefer to program in “uni-typed”
I count my past self among those smart, serious, professional people that preferred to program in uni-typed languages.
and have created some pretty fabulous stuff with them.
I’ve seen some cool demoscene projects made from m4 macros generating native assembler. Don’t think that’ll convince me to write my code in asm+m4 though.
Don’t make dishonest arguments, you’re a smart person and know full well that has entirely to do with labor input and raw numbers.
Can’t we all just enjoy our own preferences without denigrating each others?
Could, but the situation is a bit more like herd immunity and vaccination than it is gay marriage. Sadly with software we’re all tied together to varying degrees unless we’re individually prepared to go full-unabomber and not use anybody else’s stuff.
Do people have a right to refuse vaccination and spread the risk among an unknowing public?
I’m not saying people should write everything in Haskell. Rather, informed decisions should be made knowing that most comparisons currently lead to false economies. We should move forward knowing what’s been possible for the last two decades let alone what’s currently in the works (Idris et al).
As an industry, we don’t keep introducing programming languages that are a massive backwards step without there being some kind of education gap.
I wouldn’t take seriously a doctor that told me to treat my flu with bloodletting. My doctor’s opinions on bloodletting wouldn’t deserve the mutual respect of his peers either. If we want to be treated like professionals (engineers) then we should take things like this seriously. We’re using inferior tools due to preference and aversion to the unfamiliar. This is deeply unprofessional.
I think Heartbleed has demonstrated how fatal that reliance on dated tooling utilized by other people can be.
I know people that have (partly) gone the desert island route, mostly grumpy C and Forth programmers. I don’t have that choice because I code for a living.
Do people have a right to refuse vaccination and spread the risk among an unknowing public?
How about you code in your system, and I code in my system, and we agree to communicate between our systems using a exchange of uni-typed byte arrays, tagged according to a prearranged scheme. Like maybe IP datagrams.
Then at runtime we could check those incoming byte arrays and if they look sensible we can build other, higher level unityped tagged byte arrays, which we could interpret as json or maybe haskell source code or jpegs.
Then, if those arrays look OK we could, again at runtime, construct safely typed values in our systems which are isomorphic to the values which are referants of the byte arrays. Voila! Safety and happiness.
SOA has been a tactic for accommodating polyglot environments for a long time, but I don’t think that’ll work for all infrastructure.
That did introduce the amusing idea of avoiding embedding C libraries and instead exposing it as a local domain socket service.
Are dramatic parentheticals necessary for your response to my comment?
Is snobbery necessary for yours? If you’re going to label everyone either ignorant or incomprehensible, then you probably shouldn’t expect to get completely cordial responses.
This is a false economy in this case.
Why? Static and dynamic typing each have their own trade offs. That’s my only point. Your analogy perfectly demonstrated this fact.
Do you write software for a living? This stuff is a lot more impactful when you’re a professional software engineer who has to maintain systems over a period of time as opposed to writing code that works once and then is discarded.
The condescension continues. But the answer to your question is yes.
It’s not difficult at all to teach Haskell if you understand Haskell. Generally, the most difficult people to teach are the ones holding onto false analogies from programming languages that aren’t Haskell or Haskell derived.
Teaching has never been something that I’ve observed to be easy. I can’t imagine why anyone would think it’s easy. And I’ve never been in a situation where insulting or blaming the student has ever helped improve learning outcomes.
I strongly recommend taking a step back and really reading what you’re writing here. I don’t know if you intend it or not, but there is a very strong holier than thou message radiating from your choice of words. If you want to succeed in effectively communicating with as many people as possible, I’d recommend working on dropping that.
Why? Static and dynamic typing each have their own trade offs. That’s my only point. Your analogy perfectly demonstrated this fact.
They don’t, actually. That’s the false economy I’m talking about.
There are incompatible dimensions of time preference being applied here that leads to this thinking. Fixed cost/bandaid tearing vs. high, ongoing costs.
And I’ve never been in a situation where insulting or blaming the student has ever helped improve learning outcomes.
You’re not here to learn, which is why I already know this is a waste of my time.
I don’t know if you intend it or not, but there is a very strong holier than thou message radiating from your choice of words.
I’m unyielding to poor argumentation.
I respond much much better to originality, even if the argument is still bad.
I’ve heard all this a thousand times before and even used to be on the other side of the exact same arguments. I’d like to at least hear something new. I could draw up a variation of that classic Usenet “spam eradication idea” checklist for these threads and probably catch 98% of what’s said.
The question remains, what does the remaining 2% look like after the homeopathists are done complaining about not being given their due respect for their practice of alternative medicine?
I have a track record of willingness to change my mind - do you? All I’ve really gotten out of you so far is tone-policing.
Be honest, am I wasting my time here or are you just trying to make this thread go further down and to the right? Are you up for learning something new?
If I have learned anything in this industry, it’s that the dogmatic view is, with certainty approaching 1, wrong.
The fact is – in this debate, it’s not burntsushi who’s in need of a mind-change, indeed, he’s advocating for an understanding of the plain and simple fact that not everyone has the same outlook on the qualities and relative value of a language. In particular, it is not unreasonable to argue that you may be a special case, and we shouldn’t demonize people for using the tool that works for them and their team.
I say this as someone who really likes functional, strongly typed languages (I spent a fair amount of time writing exclusively Haskell, and still work it into my job occasionally, pretty sure we had a twitter conversation about it the other day).
I also say this as someone who really likes object-oriented, dynamically typed languages. I even advocate for them to be used instead of typed alternatives!
I think you are presenting the case for strongly typed languages in a very poor way, and indeed this whole thread is characteristic of the common ‘talk-past-each-other’ style, with the slight caveat that burntsushi is indeed saying something different than the usual, though in the usual style of tilting at computational windmills.
The facts are these, at the end of the day, your ideology, my ideology, everyone’s ideology is crap. What matters is results, and the fact is lots of companies make plenty of money on the backs of dynamic and static type systems. Some companies transition to or from one to the other, increasing profits in the meantime. This indicates to me the simple fact that the language and it’s characteristics, at the end of the day, are immaterial to the value a company achieves. What is more likely more important is finding the right tools, the right developers, and the right structures to support those developers and tools so that they can deliver value. Whether it’s static, strong typing in Haskell, dynamic typing in Ruby, weak-static typing in C, or butterflys-and-chaos-theory, all that matters is that value is delivered, and the fact is – both deliver, despite zealotry from both sides.
I’m not saying we should all be using Haskell for all things.
Quoting myself from earlier in this thread: “I’m not saying people should write everything in Haskell.”
The only ideologies I’m espousing are that of modernism and progress. If you don’t think CS has improved over time, then there’s a lacuna that cannot be crossed and we need not argue with each other.
The pugs Perl (self-styled post-modern programming language) 6 prototype was in Haskell :)
The only ideologies I’m espousing are that of modernism and progress.
You can either insult the people who haven’t yet reached your plateau of enlightenment or you can advocate for progress. They are mutually exclusive goals because progress requires convincing others. Convincing others doesn’t work when you insult them.
I agree – CS improves over time, nor did I mean to imply that you claimed we should all use Haskell (or anything else, other than, it seems, static typing).
That said, I think CS improves in multiple directions – including static typing, and dynamic typing. It is not unreasonable to assert that there are multiple valuable paths to travel when designing a language. Dynamic typing does have value not provided by static typing, just as static has benefits over dynamic. It’s a spectrum with more than a few critical points we can optimize toward, depending on the domain.
Perhaps the divide we are experiencing has less to do with the technical merits, and more the philosophical framework with which we evaluate these things – I view the world through a post-modern lens, I am comfortable with there being potentially many solutions a particular problem. I am making an inference (based on your last paragraph in the above) that perhaps that’s different for you, if so – fine, but let’s talk about the substance of that rather than continuing a quixotic conversation such as this one.
What are the benefits (not familiarity) of dynamic typing over modern static type systems?
Can you construct a correct program in a uni-typed language that you believe would be inexpressible in a static system?
First – I am unwilling to dismiss non-technical benefits (like ease-of-learning, etc) as they do represent real business value. But we can shelve that.
Can you construct a correct program in a uni-typed language that you believe would be inexpressible in a static system?
No, I can construct correct programs in dynamically typed languages, but by definition I should be able to construct those same programs in statically typed languages too. The principle difference is not technical – I mean, at the end of the day, you can make something work in virtually any language (barring those esoteric joke languages, while it is theoretically possible to write a webserver in befunge, I shouldn’t want to see such a thing).
You cannot examine these languages in isolation from their environment – you have to account for all the messy sociological factors that dial into the use of any tool. It’s not enough to say, “I can express that this statically typed program is correct up to the correctness of the typechecker” – you have to account for the business cost of writing that program, the peoplehours to maintain it and improve it. You also can’t treat a statically typed program in the same way as a dynamically typed one. Here is a concrete example.
I have a series of scripts which maintain an existing, shoddy webserver. I inherited these scripts from a predecessor, they were primarily bash and perl, and they were messy. Because these scripts were not efficient in terms of interface-usage-time and execution time, and because I had very little bandwidth to spare, I chose to rewrite them in ruby, rather than a static language, because the time from zero to delivery was much smaller with ruby.
Later, when these tools needed to scale up, I wanted to take advantage primarily of the useful data-parallelism libraries available in Haskell, so I rewrote chunks of the ruby scripts in Haskell. Though I was primarily re-implementing functionality, it took reasonably more time (though not inordinate) to get to feature parity with the existing rubyscripts. Eventually I added the Data-parallel stuff with relative ease (because of the library support), and went along my merry way.
Yes, it’s an anecdote, but my claim is that we’re straining at gnats – the difference in terms of value is not technical, it’s sociological. In this messy anecdote, we see the sociological constraints influencing my decision – I didn’t have the time to try to convert from bash and perl to haskell directly. Nor do I think writing the entirety of these scripts in Haskell is strictly necessary, or even cost-effective.
It is possible to overengineer a solution, and when you are optimizing to add value, overengineering causes loss. I get paid to generate value, not loss. However, when it became value-positive to use Haskell (i.e., when I wanted to do something more complicated, where I required a strong degree of correctness and wanted a reasonable time-to-delivery), then I swung that hammer.
The punchline here is that I reject any attempt to ignore the messy nature of Software Engineering to make some high-falutin' argument about the ideological purity of one idea over another. The plain fact is – from here in the real world, the use of static or dynamic languages is largely irrelevant compared to the much bigger problem of delivering software that provides the desired features (note carefully that I did not specify that that software needs to be correct, just that the customer will be able to find the features they desire).
To put it shortly: I don’t care about technical arguments, because they ignore the much bigger component of the problem, people.
What are the benefits (not familiarity) of dynamic typing over modern static type systems?
This has already been hashed out: http://stackoverflow.com/questions/125367/dynamic-type-languages-versus-static-type-languages
What jfredett said is good too. :-)
Just for fun and to give a different answer to the other good answers:
A running binary created from a decent statically typed system may be typesafe, but the information about the types is no longer reified - unless we explicitly choose to tag expressions or values with run-time tags reflecting the original compile-time types. In which case we have something strikingly similar to a ‘dynamically typed’ system. Insofar as we can then make runtime adjustments to this running binary by hotloading new code, we are doing so in a language which can only typecheck expressions (written in its syntactic representation of types) in the context of an existing set of tagged unityped values. In other words, if our program is typesafe it is only because of the tools and techniques of runtime tagging of unityped values - ie dynamic typing.
Quite easily.
The first program is represented in the second-order typed lambda calculus.
The second program is represented in the untyped lambda calculus.
They don’t, actually. That’s the false economy I’m talking about.
You haven’t presented any false economy. It isn’t necessarily just time preference, trade offs can also include personal preference, ignorance, comfort level, available libraries, performance, size of program, safety, system constraints, the people you work with, etc. All of these are factors when considering static vs. dynamic typing and they all vary depending on the particular blends of static and dynamic typing being considered.
You’re not here to learn, which is why I already know this is a waste of my time.
Spare me the theatrics. Either speaking with me is a waste of time and you stop or just press on.
Your comments are becoming vitriolic.
A key difference here is that I have a track record of willingness to change my mind (I’ve explicitly stated as much) - do you?
Be honest, am I wasting my time here or are you just trying to make this thread go further down and to the right? Are you up for learning something new?
I’m not sure what you expect. I’m already sold on functional programming. I love Haskell and have used it for several projects. Same for Standard ML and Erlang. I just stop short of zealotry, vitriol and snobbery as if the fate of the world depended on us collectively deciding to only use languages chosen by the Enlightened Few.
available libraries, performance, size of program, safety
Getting warmer :)
fate of the world depended on us collectively deciding to only use languages chosen by the Enlightened Few.
This is where I ask again if you’ve read the post I linked, because it’s core to this misunderstanding. I’m going to quote that post so I can bring this front and center.
Somebody not me said in that post: “One of the things i really love about haskell is that it makes it quite clear it isn’t the endpoint either - that there’s this whole world of dependently-typed stuff we’ll one day be able to use.”
Let something I said earlier in this thread: “As an industry, we don’t keep introducing programming languages that are a massive backwards step without there being some kind of education gap.”
I said in another earlier comment, “I’m not saying people should write everything in Haskell.”
There’s a concept of progress being emphasized here. It’s not a decision-tree whose leaves all terminate in Haskell. What is inescapable is that progress is being made in research that industry is not leveraging.
Repeating a quote from another earlier comment I made: “Do people have a right to refuse vaccination and spread the risk among an unknowing public?” with the additional thought, “Do doctors have the right to prescribe potentially harmful courses of treatment if it’s more convenient for them?”
Your answer to this is an indication of whether you’re consistent in the professional standards you hold others and yourself to.
If you believe professional standards (client outcomes) pale in importance to personal preference then there’s no reason for us to be at an impasse here. If you believe differently, then there’s a knot to be unraveled.
Did you miss that I said we shouldn’t necessarily write everything in Haskell or are you proceeding in bad-faith? I’m going to assume the latter and call it a night now.
My comments are derived crucially from this statement you made:
Knowledge of the state of the art almost always means not finding uni-typed systems very interesting. At least for practical day-to-day work anyway. We’re talking about differences on the scale of arguing in favor of outhouses rather than indoor plumbing. You won’t get serious arguments for that from people with comprehensible value preferences.
You’ve continued to argue this perspective in other comments by comparing this situation to the state of health care for the wider community. You’ve painted a picture of your position that basically boils down to something corresponding to these bullet points:
Who exactly is commenting in bad faith here? I’m arguing from the position that all things have trade offs, even the languages blessed by you. Free lunches are hard or impossible to find, and just because there’s some new PL feature introduced that improves safety at compile time doesn’t mean it’s uniformly better than the alternatives. Additional compile time safety has an extremely important trade off: complexity. As you add more safety and approach the dependently typed languages of the world, you add more complexity to your type system. What is the right trade off? There isn’t one!
It’s a balancing act. Nothing more and nothing less. This is the fundamental lesson of computer science.
I’ve talked to people that have published on augmented uni-typed systems who still didn’t know much about what writing code in more advanced languages was like, so it’s not only industrial programmers that lack exposure.
I doubt that – basically everyone who publishes on gradual typing etc has substantial experience with languages like Haskell and ML. It turns out we mostly don’t agree with you, but that’s not the same thing as lacking experience.
I started reading it a week or two ago, it’s been pretty accessible. It’s a much better fit for my learning style than Software Foundations was.
I have a friend who said the same, and we both initially learned Coq through Software Foundations.
I found the interactive style of SF more instructive. But then I did CPDT back when it had exercises, which were pretty hard compared to SF.
What about the problem Brad pointed out?
“If code doesn’t receive constant love it turns to shit,” Fitzpatrick said.
Does the Gopher team take ownership of the code?
I would be interested in what other language they are writing it in.
A formally verified version in Agda/Coq would be very interesting. I think there’s a lot that the crypto and type theory communities can learn from each other (and there’s probably a huge business opportunity here, as well!).
“With mmap, you just point to the data you want. If it’s bigger than memory …. so what?”
And if it’s bigger than your address space…? (“My solution scales so much better than your solution, right up to the point where it catastrophically stops scaling.”) I feel the rant tag is appropriate here, if only for comparing best case apples to worst case oranges.
I’d worry about the data being distributed even more than swamping a 64-bit address space.
Although, IIRC, the APL-family of languages have more to offer than just mmap — I wouldn’t adopt or abandon the languages on such a trivial analysis.
<strike>Sorry, nope.</strike> No. Functional programming gives primacy to value transformations as the means to express computation, and for this style to work, the language must have interesting (nontrivial) observational equivalences between expressions. (Note that purity, in the Haskell sense, is a sufficient but by no means necessary condition.) For example, in ML, the functions
fn (x: int) => x + xandfn x => 2 * xare indistinguishable from the other, and so are the lists[1,2,3]andrev (rev [1,2,3]). Their C# counterparts could be distinguished by object identity. Very few languages support functional programming reasonably well.I don’t see how the fact that there exists a means to distinguish values by object identity in a given language makes it impossible to program in a functional style in that language. This is also a bit idiosyncratic as a litmus test for functional programming (not that FP has any shortage of idiosyncratic litmus tests).
Functional programming imposes restrictions on otherwise imperative programming, in the hope that programs that satisfy this restriction are easier to manipulate as mathematical objects, both formally and informally. This restriction comes with an expressiveness price. For example, FP limits the kinds of nondeterminism that can be expressed in a program, because the lambda calculus is Church-Rosser: if you evaluate a lambda term twice, and both times arrive at an answer (normal form), then both times you arrive at the same answer.
A general-purpose programming language can’t be purely functional only. For example, Haskell has IO actions, and which are executed, not evaluated. However, a programming language can make it easier to implement parts of a program in a functional style, and integrate them with other parts implemented in a more traditional imperative style. For this to work, you need a guarantee that the imperative parts won’t compromise the abstractions that the functional parts depend on. Pervasive object identities compromise the irrelevance of the choice between multiple representations of the same value.
The traditional solution in these kinds of mixed languages (Lisp, for example) is that if you don’t want to compare objects by object identity, you compare them according to a different kind of identity, which is why there are several kinds of equality predicates in Lisp. It’s an unusual argument (although not unheard of) to argue that the existence of an equality predicate that you don’t want to use makes the language impossible to program in a functional style.
In any case, my broader point is that this isn’t some kind of new issue, and how “functional” various choices make a language has dozens of definitions. I don’t think the fact that you personally prefer one idiosyncratic definition of this decades-old contested term justifies starting a comment with an arrogant, dismissive “Sorry, nope”.
Common Lisp isn’t a “mixed” language. It’s object-oriented, and the real notion of equality is physical object equality (
eq), period. Everything else is just a convenience. For example,equaltells you something about the state of two objects, not whether the objects are really the same.Removing
eqfrom the language doesn’t make the problem go away. Even ifeqdidn’t exist, you can provide evidence that two supposedlyequalobjects are actually physically distinct by mutating just one of them.I apologize for the “Sorry, nope.”
I don’t think you can have a historically coherent definition of the term “functional programming” that doesn’t include Lisp, which was the first widely researched and used language considered to support a functional style of programming. Until roughly the late 80s / early 90s, when other more-strictly-functional languages eclipsed it, it was even often seen as the canonical FP language, though of course not everyone agreed (in “Lisp” here I’m including Scheme, which probably had a larger FP-oriented community than Common Lisp did). From 1982 to 1994, for example, one of the main academic FP conferences was named “ACM Symposium on Lisp and Functional Programming”. It published work situated in a variety of languages (including the ML family and Haskell), but Lisp had a dominant position. Once Lisp began waning, in 1996 that conference merged with another one to become the International Conference on Functional Programming (ICFP), today’s biggest FP conference.
Now certainly you can say “the definition of FP has shifted over time”, but I think it’s not so much shifted as become a family-resemblance term with a dozen or so definitions, like “object-oriented”. Yes, there are Kay disciples who will claim that there is one true definition of OO (and Java isn’t OO), but they haven’t really won out.
The risk of asking to include Lisp at all costs is that you’re making functional programming impossible to distinguish from object-oriented programming. Citing a researcher on and proponent of object-object oriented programming:
First-class procedures are thus objects with a single operation.
Yes, it is an observed social phenomenon that the Scheme community has traditionally appreciated programming in a functional style. (It is also an observed social phenomenon that some C++ programmers appreciate programming in a functional style, and other C++ programmers call the former “crazy”.) However, from a purely technical point of view, there is no well-defined functional subset of Scheme that can safely interact with imperative Scheme programs, without compromising the abstractions defined in the functional subset.
I don’t understand the defensive reaction when I say that such and such language doesn’t support functional programming very well. I’m not saying “it’s useless” or “you can’t write clean code in it”. I’m just saying “it isn’t terribly convenient to program in a functional style in it”. And that’s fine - no single language can support all styles and do it well.
I suspect that the defensive attitude comes from the “trendiness” of functional programming in certain very vocal circles, and the subsequent rush of language designers to add “functional features” to their languages. This is dangerously reminiscent of what happened to object-orientation since the 80’s. Alas, this causes more harm than good (as this very thread shows), and, in any case, it can’t possibly work: what is needed isn’t “more features”, but rather “more restrictions on what existing features can do” and even “less features”.
Thanks, I found this reply helpful / clarifying, and largely agree.
I have never seen this definition before and am inclined to believe that it is one you made up, rather than what is commonly meant by the term.
Do you have any citations that this is what is commonly implied by the term “functional programming”?
Source
Your most contentious claim, namely that object identity disallows computation by evaluation by its existence, is neither mentioned nor supported by Dr. Harper’s article.
I didn’t claim that object identities disallow computation by evaluation. However, when object identities are pervasively involved in all calculations, the values you are manipulating are the object identities themsevles, not the standard mathematical concepts Dr. Harper talks about. For example, when you evaluate twice the Lisp expression
(list 1 2 3), you get two different results: the identities of two different cons cells. Languages that support functional programming avoid this unfortunate situation by natively treating many common mathematical constructions (tuples, lists, trees, etc.) as values.I fail to see the practical implications of this. As long as you agree by convention to not compare function types by reference identity, what impediment do you have to programming in a functional style?
Your example of creating two lists doesn’t paint a clear picture for C#, since most complex object types define structural comparisons that would be used in most cases.
Conventions come in two kinds: enforced (statically or dynamically) and broken.
As I stated before, it doesn’t suffice to have the right equality predicate. Equal objects must actually be indistinguishable.
Up to you if you want to take such a hard line. My experience is that value is not a step function.
So ML has some way of determining whether two algorithms implement the same function? That would be an enormous advance.
For reference this is actually impossible by Rice’s theorem (which, in extreme brief, states that you can’t always tell what an algorithm will do). It’s actually strikingly easy to prove by reduction to the halting problem, and it’s my favorite result in computer science, because it’s both very general and simple and elegant to prove.
No. Function equality is undecidable in ML. “Being equal” doesn’t imply “can algorithmically be determined to be equal”.
I fail to understand how stating a long-known mathematical fact is being a troll. The existence of the notion of equality doesn’t imply that it has to be algorithmically decidable. For example:
Could the downvoter please explain?
So what does: “ For example, in ML, the functions fn (x: int) => x + x and fn x => 2 * x are indistinguishable from the other, ” mean then?
if f x = x+x and g x = x*x were “indistinguishable”, I’d assume the compiler could optimize h(g 5, f 5) by reusing g 5
Two expressions being indistinguishable means replacing one with the other in any larger program doesn’t alter the meaning of the larger program.
Ok. So, similarly, “In C, the expressions (x+x) and 2*x are indistinguishable”? In fact, optimizing compilers will replace the multiply with a shift.
Yep. The expressions
x+xand2*xby themselves are indistinguishable in C. However, if you defineThen
fooandbar, as function pointers, are not indistinguishable.But since ML is unable to determine whether two algorithms implement the same map, what is the actual difference? ML cannot replace f with g and actually treat them as “indistinguishable” unless it can determine that they are equal as functions which is impossible in general and exceptionally difficult even for restricted cases. So it appears that your claim means nothing at all.
Function equality being undecidable means that there’s no algorithm for testing whether two arbitrary functions are equal. That’s why, if you write the expression
(fn x => x + x) = (fn x => 2 * x), you get a type error: the typeint -> intisn’t aneqtype.However, an optimizing compiler doesn’t need to decide whether two arbitrary expressions are equal. It is sufficient to have an algorithm with three possible results: “equal”, “not equal” and “don’t know”. Only when the algorithm returns “equal”, can the compiler use this equality to optimize your program.
So they are distinguishable. Which was my point. ML is a programming language and as such is subject to the same limitations that dog all languages in which algorithms are definable.
No, that is wrong:
fn x => x + xandfn x => 2 * xare not distinguishable. Both denote the same mathematical function - provably so, even!Your argument here is from the perspective of the compiler making optimizations. All equivalence says is that the optimization is valid, it doesn’t say anything about the feasibility of implementing the optimization. Furthermore there are reasons to care about equivalences beyond optimization.
My point was simply that ML “functional” nature does nothing to make this difficult problem magically go away.
If you make a plan that depends on your ability to make unicorns appear out of nowhere, you know that the plan is fundamentally flawed and can’t be carried out, right? The situation is very similar here: Algorithmically deciding whether two arbitrary functions are equal is known to be impossible, so you better don’t try in the first place.
However, it’s possible to implement a procedure that, given two expressions (that is, syntax trees), answers either (0) “they’re surely equal” or (1) “they might or might not be equal”. For one, a procedure that always answers (1) meets the specification! We’re interested in procedures that sometimes answer (0), though, of course.