Why Go? Use Racket
cxwangyi.wordpress.com
cxwangyi.wordpress.com
I feel like the author hasn't used go much. You almost never work with arrays directly, you use slices, which CAN be efficiently passed around.
EDIT: Upon re-reading I think the author was making a point about the consistency of go, and how different types have different behavior with regards to pass-by-reference/copy. There's actually a pretty simple rule for it:
If the variable is a primitive, or defined by the user, it is passed by copy (ints, strings, structs, etc...). Everything else (compositional types like slices and maps, and others like channels) are passed by reference.
The outlier are raw arrays, but again you don't ever actually use those, so you can just ignore them.
But the complexity that comes with it is undeniable. It's not just one exception that is confusing. The whole business with nil interface values versus non-nil interface values that contain nil pointers is not exactly pretty. It is consistent though.
fn spam(victim: channel)
takes the channel by value (impossible in Go, and probably nonsensical anyway), whereas:
fn spam(victim: @channel)
takes a pointer to the channel.
I think the str type is currently an exception to this in Rust.
Everything in Go is passed by copying its value.
However, slices, maps, channels, and interfaces all have small values, which are just a pointer and some other small data (length, type, etc), so passing them directly (rather than by pointer) is not a big deal.
For someone coming from a Scala background, I feel this statement is absurd.
One thing we are all forgetting here is that anyone can prove language X is better than Y. But it's always wise to choose the best tool for the job (X is better than Z in doing what exactly?).
Languages and frameworks are a personal preference. You choose them based on their philosophises and if their philosophies resonate with yours.
After a certain point, language choices will no longer matter. Your end goal, should be to get to this point, instead of fighting over them. Just my 2 cents.
That said, I think Racket is so-so cool.
The specific example he used was how a programmer needs to know exactly how some different types are passed as arguments to know what the most efficient way is, since it's not entirely consistent.
EDIT: I agree with the rest of your comment, though. Languages are just tools. The whole, "Why are you using X? Y is better," thing is getting old.
I'm so tired of this meme. Yes, in some situations there is a "right tool". If you are working on embedded devices you probably should just use C. But in the wider world of programming there isn't a "right tool". In web development especially, there are many tools that can get you to the same place. And because of that it's perfectly reasonable to debate that one is better/worse than another.
Languages are personal preferences; they certainly have objective differences which have some effect on utility, but a substantial part of what makes a language the best for a particular programmer for a particular purpose is how well the the language matches the programmer's experience and patterns of thought for addressing the problem domain. These are inherently subjective factors.
> In order to join forces to work on demanding projects, I think we need to agree on a relatively small number of good-enough languages.
We may need to agree, for large projects that need to be integrated in such a way that you can't use a mix of languages for different components, on as few as one language for a particular project, but that doesn't constrain the number of languages we can have in the whole programming ecosystem (and, indeed, restricting the domain of available languages would restrict the development of new techniques and languages and the development of better languages for new use case.)
> To do this, we need objective criteria for choosing one language that is good for a particular class of software.
This requires, obviously, the ability to objectively categorize software into "classes" to apply the criteria. Since I think you are going to fall down hard on that, I'm not really holding my breath to seeing your vision realized, even if I thought it was a good thing.
And unlike most other languages, it's out of box support for Windows is perfect.
The case I'd make: The shiny new feature X in today's fashionable new lang Y? Racket probably does this, does it elegantly, and has done it for awhile.
CSP is just one example. It's great that Go is helping popularize it.
Also I'd headline it as, "Intrigued by __? Also try Racket!".
Racket draws on a lot of PL research (which is why it probably already has feature X) but is also very practical. It's easy to install and use on all platforms. There's also a wonderful community.
About the only thing it lacks is a BFD/cult leader phenom such as some companies and langs have. ;)
For beginners, it's an easy to learn language with an easy to setup programming environment.
For advanced programmers, there're a lot of advanced features available as 6cxs2hd6 mentioned.
Go's type system is not complex at all. What is complex about it? There is a limited set of types, and they can have methods. You can define your own types. What's so complex about that?
> programmers need to know all the details about the implementation of standard types, before they can use them correctly.
You should not have problem with knowing the details of the language or the third party libraries you are using if you want to be a proficient engineer builds stable, secure and easily-maintainable systems.
That's true only to a point. I'm not sure how deep the dependency tree of the two main Java projects I work on at the moment is, but I can guarantee that I don't know "all the details" of, well, most of it, despite considering myself a "proficient engineer".
What if you instead want/have to be a pragmatic programmer, you doesn't "engineer stable, secure and easily-maintainable systems" with all the time of the world available to him, but has to build something working adequate enough, as quick as possible, warts and all?
You know, like 90% of early startup code out there, including companies that sold for hundrends of millions.
Similarly for painting; you're looking at a world of difference between watercolor and oil (just to pick two examples), and what you chose depends on the goals.
I'm not sure your metaphor was as useful as you'd like.
"Racket programs build and run much slower than Go programs."
Edit: By this I meant to be agreeing with the above statement that someone will come along and write a post about why Go is better - it's already been done in this one post. Sorry for the misunderstanding..
Obviously, sometimes execution speed is important, and sometimes it isn't - it depends on what you are trying to do.
That said, of course it isn't "really relevant". Or, at least, it's not all that matters, if Racket offers a superior experience otherwise AND its speed is adequate for the task.
Else we'd use C all the time, and nobody would use Python or whatever higher level language.
http://cxwangyi.wordpress.com/2012/07/29/chinese-whispers-in...
To me, the speed at which the code executes is a second derivative problem - this is to say that if a language gets version 0.1 deployed two months faster, then it is faster in a more important sense. A hammer and screws is more useful than a screwdriver and nails - intact it is more useful than a Phillips screwdriver and slotted screws.
As well as speed being a secondary concern for all but a few application domains.
Each thread reads from the channel to its left and writes the processed input into the channel to its right.
Except that the programs he posted are flowing the other way(start with rightmost, read final value from leftmost). The implementation of the author's wording needs a slight change.
Go implementation:
package main
import "fmt"
func setup_channels(left chan int, num int) chan int {
for i := 0; i < num; i++ {
right := make(chan int)
go func(left, right chan int) { right <- 1 + <-left }(left, right)
left = right
}
return left
}
func main() {
leftmost := make(chan int)
rightmost := setup_channels(leftmost, 100000)
leftmost <- 1
fmt.Println(<-rightmost)
}
Racket implementation: #lang racket
(define (setup-channels left idx num)
(if (>= idx num)
left
(let [(right (make-channel))]
(thread (λ ()
(channel-put right (+ 1 (channel-get left)))))
(setup-channels right (add1 idx) num))))
(let* [(leftmost (make-channel))
(rightmost (setup-channels leftmost 0 100000))]
(channel-put leftmost 1)
(channel-get rightmost))
I also don't understand why is he writing to the leftmost channel in a separate thread. I don't think that's needed.I feel like a non-linux user categorizing Debian, Ubuntu, Mint, Red Hat, and so on altogether as 'Linux'; While he's not incorrect, there are subtle difference that he's not seeing. It feels rather frustrating. I'm using Racket(when I want to experiment in functional language) because that's what I'm used to, but it would be great to hear X and Y are different in ... than X is better than Y because...
type tree = Leaf of int | Node of tree * tree
let rec exists_leaf test tree = match tree with | Leaf v -> test v | Node (left, right) -> exists_leaf test left || exists_leaf test right
let has_even_leaf tree = exists_leaf (fun n -> n mod 2 = 0) tree
I appreciate the "generally" word here. Racket and Chicken Scheme for instance, both provide statically type extensions.
----
[1] http://docs.racket-lang.org/ts-guide/quick.html
[2] http://docs.racket-lang.org/ts-guide/more.html#(part._.Type_...
One of the main benefits of static typing is to detect errors at compile time which is a benefit of typed Scheme compilers too.
BTW, static typing goes way before Java :)
Obviously. But a static type system that lacks power and expressiveness is very constraining and can detect very few classes of errors. Hence the example of java, a very inexpressive static type system.
>BTW, static typing goes way before Java :)
Again, obviously. Why are you saying random obvious things to me?
It's unclear what you mean by "Java-style static typing" then, because the Java type system and Typed Racket's type system are completely different.
One actually has local type inference (which is not "crappy" type inference necessarily; HM-style type inference is notoriously brittle), the other doesn't. One has nominal class types, the other has no class types (yet). One has intersection types, occurrence typing, "true" union types, and so on, while the other has none of those. One has bounded polymorphism, the other has System F-like polymorphism. One of them has variable-arity polymorphism, while the other doesn't. The list goes on.
In fact, aside from being explicitly typed, there are few similarities.
Which is totally orthogonal to the power and expressiveness of the type system. I specifically gave an example that C# also has crappy limited type inference too, and is still java-style static typing.
>HM-style type inference is notoriously brittle
Yeah, obviously no languages could possibly exist that use it with no problems.
>One has nominal class types, the other has no class types (yet)
What does being OO have to do with anything? I am talking about the expressiveness of the type system. The amount of things you can express in the type system.
>One has intersection types, occurrence typing, "true" union types
So racket has a partial implementation of ADTs? And that's it? Ok, you win, racket has java + 0.1 level of static typing, hooray! The point is, using static typing in racket gets you virtually nothing, because it is such a primitive type system. Go use ML or haskell and then compare it to typed racket.
And Racket's type system (being an expandable, routinely expanded language) is much, much larger.
Is the same true for Racket threads? Or are they closer to "lightweight" green threads in other languages. I'm genuinely curious. If they are really as lightweight as goroutines, that should be publicized more heavily. If they're not, then it's disingenuous to claim that Racket's CSP story is equivalent to Go's.
http://benchmarksgame.alioth.debian.org/u64/benchmark.php?te...
As a user of web sites (and a web developer), I find it disappointing and frustrating to use web sites designed by people who clearly have not made performance a priority. So just as a tangential point: if you are one of those web developers who loves doing things on slower platforms, believing that it's just fine to disregard performance, please think of your users! We are the ones who suffer! 250ms here, 500ms there, sometimes over 1,000ms before the server responds with the first byte! It adds up to an annoying user experience.
Among popular sites, those that are slow tend to really irk me, and I seek out alternatives. For example, there is this very popular source code social network site...
Let's put that aside, however.
What I am talking about is a real request to a non-cachable dynamic page or service endpoint. It's the frustration of "Waiting for [servername]..." status bar messages. It's the frustration of looking at the Network panel in Chrome or Firebug and realizing that it's just spinning waiting for the first byte of the response. It might be a server-templated HTML page. It might be an API call fetching some JSON. But the sorry state even in 2013 is that a disturbingly large number of sites will spend hundreds of milliseconds, and in some cases full seconds to respond to dynamic requests that ultimately deliver quite trivial response payloads.
I for one want developers to stop sweeping these performance failures under the rug by deflecting server-side performance failure with client-side cover.
So it's just insignificant (performance-wise) whenever you write site in carefully optimized C or just write some Ruby magic that performs, say, 100x slower. 1ns vs 100ns is insignificant when it's your database that responds in 300ms.
Each application is its own unique snowflake, admittedly, but I encourage web developers to profile their applications to understand where server time is actually consumed. Furthermore, I implore you to realize that time spent in the ORM is not the same as time waiting for the database. If your profiler conflates ORM machinations as database time, you are not seeing the correct data.
Modern databases are extremely efficient at fetching data from well-indexed tables. They are in many cases not the bottleneck although conventional wisdom would have you believe otherwise.
In our experience, slower platforms consume an impressively large amount of time doing things unrelated to the actual database queries. Under load, the database server can be nearly idle while the application server is falling over itself in its slow ORM, its template engine, or helper functions. Meanwhile, faster platforms mean faster frameworks, faster ORMs, and faster templates. These platforms can easily saturate the Gigabit Ethernet connection to their database server without the database server hiccuping.
Something is indeed wrong. We tolerate servers responding to trivial requests in hundreds of milliseconds (sometimes even greater than 1,000 milliseconds!)
Here is an off-the-cuff--not cherry picked--screen grab from Firebug [1] showing 342ms of waiting for the server to respond to a relatively trivial request of listing summary information about approximately 20 entities that are presumably stored as rows in a database table from a popular web site. This type of delay is my chief complaint about a site that I am otherwise very fond of. Until this first response is delivered, the user is just plain waiting. Static assets should also arrive quickly, but I am more forgiving of them arriving gradually to decorate the page.
Yes, it's certainly possible the database server is the origin of this pain. And web developers should profile their applications to gain insight. Unfortunately, as I mentioned above, many profilers incorrectly conflate ORM or platform database driver time with genuine database time. Given what we have seen from frameworks and platforms making database queries and processing responses through ORMs, I know that MySQL (and other data platforms) on decent hardware can respond to tens of thousands of such trivial queries per second. Meanwhile, some application stacks reach reduced responsiveness and worsened user experience well before the database's CPU and disk register more than a blip.
Web application performance will have its exceptional cases. But in general, I find Java web application when modestly-well architected, will respond in low tens of milliseconds--and in many cases single-digits--to the vast majority of their routes. A PHP developer would need to be nearly superhuman to accomplish the same level of performance.
I don't quite follow this "problem" - it sounds like a complaint about the lack of generics. I haven't been programming in Go for long, but I found the reflection system pretty easy to use and it basically allows you to do this.
Sure, it's not EXACTLY the same, but in what case do I actually need a float or integer instead of an interface method that acts on them in the way I expect?
Is there a great reason to use racket instead of go?
Racket has a richer set of concurrency/parallelism structures (threads, futures, places, engines) than Go provides (goroutines). This is both a source of power, and a source of cognitive overhead.
Probably only Oberon-7 strives to be simpler, from the current set of modern languages.
Right, I always forget the right naming. From the Oberon family, I prefer Active Oberon anyway.
> .., which has so few users, I doubt it qualifies as valid option.
True, it is unfortunate that the whole Oberon ecosystem never left the academia, except for a single digit set of companies that managed to make some money out of it.
Still, it does count when discussing about language type systems.
My experience with it, made me a supporter of GC enabled systems programming languages and OS made with them.
The other one I also played with was Modula-3.
Nowadays it seems even at ETHZ, Oberon does not get used that much, if at all and they switched their focus to research based on .NET.
> I would love to see some form of Oberon gain more nerd traction.
I doubt it will ever get one, due to its Pascal syntax heritage, which many don't like, specially the all caps for keywords.
Oh well, at least Go got some influence from it.