Things from Python I'd miss in Go

Let's assume Go has one killer feature – cheap concurrency – not present in any other language with similar serial performance (ruling out say Erlang). And let's agree that it gives Go its perfect niche – and we're only discussing uses of Go outside that niche from now on. So we won't come back to concurrency till the very end of the discussion. (Update – the "killer concurrency" assumption seems false… but anyway, we'll get to it later.)

***

Brian Kernighan once called Java "strongly-hyped". Certainly his ex-colleagues' Go language is one of the more strongly-hyped languages of today – and it happens to have a lot in common with Java in terms of what it does for you.

Rob Pike said he thought C++ programmers would switch to Go but it's Python programmers who end up switching. Perhaps some do; I, for one, am a Python programmer not planning to switch to Go – nor will I switch to Go from (the despicable) C++ or (the passable) C.

Why so?

What does Go have that C++ lacks? Mandatory garbage collection, memory safety, reflection, faster build times, modest runtime overhead. C++ programmers who wanted that switched to Java years ago. Those who still stick to C++, after all these years, either really can't live with the "overheads" (real time apps – those are waiting for Rust to mature), or think they can't (and nothing will convince them except a competitor eventually forcing their employer out of business).

What does Go have that Python lacks? Performance, static typing. But – again – if I needed that, I would have switched to Java from Python years before Go came along. Right?

Maybe not; maybe Java is more verbose than Go – especially before Java 8. Now, however, I'd certainly look at Java, though perhaps Go would still come out on top…

Except there are features I need that Go lacks (most of which Java lacks as well). Here's a list:

Dynamic code loading/eval

Many, many Python uses cases at work involve loading code from locations only known at run time – with imp.load_source, eval or similar. A couple of build systems we use do it, for instance – build.py program-definition.py, that kind of thing. Also compilers where the front-end evals (user's) Python code, building up the definitions that the back-end (compiler's code) then compiles down to something – especially nice for prototyping.

I don't think Go has a complete, working eval. So all those use cases seem basically impossible – though in theory you could try to build the eval'ing and eval'd code on the fly… Maybe in some cases it'd work. Certainly it's not something Go is designed for.

REPL

No REPL in Go – a consequence of not having eval. There are a few programs compiling Go on the fly, like go-repl, but you can't quite build up arbitrary state that way – you're not creating objects that "live" inside the session. Not to mention the following little behavior of Go – a production-friendly but prototyping-hostile language if there ever was one:

> + fmt
! fmt> fmt.Println("Hello, world!")
Hello, world!
! fmt> println("This won't work since fmt doesn't get used.")
Compile error: /tmp/gorepl.go:2: imported and not used: fmt

At home, I use DreamPie because I'm on Windows, where a scanner and a Wacom tablet work effortlessly, but there's no tcsh running under xterm. Perhaps go-repl could replace DreamPie – after all, you can't exactly build up state in live objects in tcsh which I'm quite used to. But I kinda got used to having "live objects" in DreamPie as a side effect of using it instead of tcsh.

And certainly Python REPLs already did and always will get more love than Go's because Python is designed for this kind of thing and Go is not.

numpy

So Python is slow and Go is fast, and just as readable, right? Try doing linear algebra with large matrices.

Python has numpy which can be configured as a thin wrapper around libraries like Intel's MKL – utilizing all of your cores and SIMD units, basically unbeatable even if you drop down to assembly. And the syntax is nice enough due to operator overloading.

Go doesn't have operator overloading, making scientific computing people or game programmers cringe. Go is ugly when it comes to linear algebra. Will it at least be as fast as Python with MKL? I doubt it – who'll continuously invest efforts to make something hopelessly ugly somewhat faster at these things? Even if someone does – even if someone did – who cares?

Why not have operator overloading? For the same reasons Java doesn't: "needless complexity". At least in Go there's a "real" reason – no exceptions, without which how would you handle errors in overloaded operators? Which brings us to…

No exceptions

Meaning that every time I open a file I need to clutter my code with an error handling path. If I want higher-level error context I need to propagate the error upwards, with an if at every function call along the way.

Maybe it makes sense for production servers. For code deployed internally it just makes it that much longer – and often error context will be simply omitted.

More code, less done. Yuck.

Update: a commenter pointed out, rather empathically I might add, that you can panic() instead of throwing an exception, and recover() instead of catching it, and defer() does what finally does elsewhere. Another commenter replied that the flow will be different in Go in some cases, because defer() works at a function level so you effectively need a function where you could use a try/finally block elsewhere.

So the tendency to return error descriptions instead of "panicking" is a library design style more than strictly a necessity. This doesn't change my conclusions, because I'd be using libraries a lot and most would use that style. (And libraries panicking a lot might get gnarly to use because of defer/recover not working quite like try/finally; "strict necessities" are not that different from this sort of "style choice".)

GUI bindings

We use Python's Qt bindings in several places at work. Go's Qt bindings are "not recommended for any real use" yet/"are at an alpha stage".

This might change perhaps – I don't know how hard making such bindings is. Certainly concurrent servers have no GUI and Go's designers and much of its community don't care about this aspect of programming.

Not unlike the numpy situation, not? Partly it's simply a question of who's been around for more time, partly of what everyone's priorities are.

All those things, combined

We have at work this largish program full of plugins that visualizes various things atop video clips, and we're in the process of making it support some kinds of increasingly interactive programming/its own REPL. Without eval, operator overloading for numeric stuff, the right GUI bindings or exceptions it doesn't seem easy to do this kind of thing. To take a generally recognizable example – Python can work as a Matlab replacement for some, Go can't.

Or, we do distributed machine learning, with numpy. What would we do in Go? Also – would its concurrency support help distribute the work? Of course not – we use multiple processes which Go doesn't directly support, and we have no use for multiple threads/goroutines/whatever.

Conclusion

Just looking at "requirements" – ignoring issues of "taste/convenience" like list comprehensions, keyword arguments/function forwarding etc. – shows that Go is no replacement for Python (at least to the extent that I got its feature set right).

What is Go really good at? Concurrent servers.

Which mature language Go competes with most directly? Java: rather fast (modulo gc/bounds checking), rather static (modulo reflection/polymorphic calls), rather safe (modulo – funnily enough – shared state concurrency bugs). Similar philosophies as well, resulting in feature set similarities such as lack of operator overloading – and a similar kind of hype.

(Updated thanks to an HN commenter) Does Go have a clear edge over Java when it comes to concurrency? With Quasar/Pulsar, maybe not anymore, though I haven't looked deep enough into either. Certainly if you're thinking about using Go, Java seems to be a worthy option to consider as well.

Would I rather be programming in Go than C or C++? Yes, but I can't. Would I rather be programming in Go than Python? Typically no, and I won't.

P.S.

Is there a large class of Python programmers who might switch to Go? Perhaps – people working on any kind of web server back-end code (blogs, wikis, shops, whatever). Here the question is what it takes to optimize a typical web site for performance.

If most of the load, in most sites, can be reduced drastically by say caching pages, maybe learning a relatively new language with a small community, less libraries and narrower applicability isn't worth it for most people. If on the other hand most code in most websites matters a lot for performance, then maybe you want Go (assuming other languages with similar runtime performance lack the cheap concurrency support).

I'm not that knowledgeable about server code so I might be off. But judging by the amount of stuff done in slow languages on the web over the years, and working just fine (Wikipedia looks like a good example of a very big but "static enough" site), maybe Go is a language for a small share of the server code out there. There are however Facebook/Twitter-like services which apparently proved "too dynamic" for slow languages.

Which kind of service is more typical might determine how much momentum Go ultimately gains. Outside servers – IMO if it gains any popularity, it will be a side-effect of its uses in servers. (And the result – such as doing linear algebra in Go – might be as ugly as using Node.js for server-side concurrency, "leveraging" JavaScript's popularity…)

And – why Python programmers would then be switching to Go but not C++ programmers? Because nobody is crazy enough to write web sites in C++ in the first place…

150 comments ↓

#1 David R. MacIver on 06.09.14 at 10:43 pm

"Because nobody is crazy enough to write web sites in C++ in the first place…"

Except (infamously) okcupid

#2 Yossi Kreinin on 06.09.14 at 10:53 pm

Seriously? All of it? Any interesting outcomes (like, I dunno, frisky messages to one user reaching another because of memory overruns or such?)

#3 Sundar on 06.09.14 at 11:25 pm

"Any interesting outcomes (like, I dunno, frisky messages to one user reaching another because of memory overruns or such?)"

Well, I hadn't seen any until today, but came across this on reddit only a minute ago: http://i.imgur.com/QDNSu0a.jpg Apparently, that's the maximum value for an unsigned 64 bit integer, so there's your integer underflow (I wonder why -1 people like him though, poor guy).

#4 Norman Yarvin on 06.09.14 at 11:37 pm

Go does sort of have exceptions:

http://blog.golang.org/defer-panic-and-recover

They're perhaps not quite the sort you'd want, but they are enough to make it so that you don't need to stick an if statement after every function call.

But as for "try doing linear algebra with large matrices", hell, try _declaring_ large matrices. Go doesn't make it easy. It has arrays, and you can make arrays of arrays (so far so good), but arrays are constant size, so you can't write a function that takes an N by N array of arrays as an input. For variable length arrays, Go has slices… but they're only one-dimensional. If you want two dimensions, you've got to use slices of slices, or use a single slice and do the address arithmetic by hand.

They actually could add multidimensional slices quite reasonably and cleanly, and I've told them they should, but they're not particularly interested:

https://code.google.com/p/go/issues/detail?id=6282

https://docs.google.com/document/d/1xHyOK3hSxwMtyMH-pbXSXxo7Td9A_Teoj6cbr9ECeLM

#5 Yossi Kreinin on 06.10.14 at 12:35 am

-1 likes – probably another bug… A joke about C++, coupling and decoupling seems fitting but I can't think of any.

Regarding defer, panic and recover – don't I need to stick a recover at every call if I want to log the call stack? And, I'd still need an if checking the error returned by opening files, right?

Regarding slices… yeah. C++ "mitigates" this problem with operator overloading as it does the problem of computing things given the matrices (and operator overloading is in itself not a great feature for a language like C++…)

#6 David R. MacIver on 06.10.14 at 3:14 am

Yossi: Not many that I know of. It's surprisingly reliable.

They've got their own webserver written in C++ (https://github.com/okws/okws) and do everything embedded in that. It's the sort of thing that should have gone horribly wrong and somehow seems not to have.

#7 Hraban on 06.10.14 at 3:51 am

Hi,

Don't forget generics / operator overloading / macros / anything that solves this:

http://godoc.org/flag#pkg-index

or:

http://godoc.org/sync/atomic#pkg-index

So much copy/pasting. And when you create your own library with type-agnostic functionality, you must follow the same pattern.

In practice, a lot of Go projects reimplement basic datastructures for their own datatypes. Result: bugs in code that shouldn't have been written in the first place.

Go semantics are so simplistic, it feels like a compilation target for a language with AST macros.

#8 Hraban on 06.10.14 at 3:52 am

Hi,

Don't forget generics / method overloading / macros / anything that solves this:

http://godoc.org/flag#pkg-index

or:

http://godoc.org/sync/atomic#pkg-index

So much copy/pasting. And when you create your own library with type-agnostic functionality, you must follow the same pattern.

In practice, a lot of Go projects reimplement basic datastructures for their own datatypes. Result: bugs in code that shouldn't have been written in the first place.

Go semantics are so simplistic, it feels like a compilation target for a language with AST macros.

#9 Caleb Cushing on 06.10.14 at 5:00 am

REPL, you know it surprises me that this is a requirement… I've never used one beyond learning a language, this only seems like it'd be useful when setting a breakpoint in a debugger and having it drop me to the REPL. I'd like to know what people who really make use of these really do with them.

#10 Bill Mill on 06.10.14 at 5:23 am

Caleb: Sometimes (depending on the task), I tend to build up my programs interactively at the REPL, testing little pieces of them there and moving them over into the code when they work. IPython is a superb tool for doing so, I recommend trying that style at least once.

#11 lmm on 06.10.14 at 5:39 am

I went from primarily-python to primarily-scala, so I'm curious how much you'd miss doing that. Scala probably doesn't have the linear algebra case down yet (though Spire is working at it), but we've got type-safety and performance without the verbosity of Java, we've got some limited form of eval (as a Java scripting engine) and a fully-functional REPL, we've got operator overloading and exceptions, and the JVM Qt bindings (smoke) are reasonably mature, though I can't speak to how easy it is to use them in idiomatic scala.

#12 smoe on 06.10.14 at 5:53 am

Caleb: REPL is definitely the feature I miss most in Go so far. For me its extremely handy in the following situations
- Debugging errors.
- Evaluating new libs
- Playing around with json apis
- Developing an idea without the distraction of the application it is surrounded
- Quickly modify objects with an orm
- Convert/restructure things
- Aa a calculator :)

#13 Jonathan Eunice on 06.10.14 at 6:27 am

I hear a lot about Python programmers embracing and flocking toward Go, but the cases I've seen detailed (e.g. Space Monkey) seem to be very much "well, duh!" situations: places concurrency & efficiency rule, and where the things that are great about Python are less critical.

I certainly wish Python had better out-of-the-box concurrency and efficiency. But I wouldn't give up its clarity, exceptions, reflection, or ecosystem unless I really, really had to.

For Pythonistas keener on the new-language shuffle, consider Julia as an option to Go. It's progressively typed, compiled with C/Java-like performance, and has rich metaprogramming. If I had to "leave Python for performance" (i.e. if PyPy and similar still not fast enough), Julia'd be worth a serious look.

#14 George on 06.10.14 at 6:36 am

Hmm I think python devs are changing from python to go cause of the differences between 2 and 3… And you can see how 2 is viable but python 3… who really wants to use it at the moment?

#15 junk science on 06.10.14 at 6:51 am

play.golang.org is not a full substitute for a REPL, but it is often enough for simple testing of ideas or syntax

Go is correct on "exceptions" despite your misgivings!

eval()…in twenty years of perl I never used it, so I don't miss it in Go

#16 Bob on 06.10.14 at 7:04 am

Exceptions are one of the features I hope NEVER gets put into Go. When I look at systemically buggy production code in Java the inability to debug the problem can, almost always, be traced back to exception handling. Seriously, how did we get the point were error checking is getting handled by the 21 century version of a goto statement?

#17 Wayne on 06.10.14 at 7:36 am

I'll stick with C# where I get every convenient language feature, the best tooling and good enough performance (better than Python at least) on the most stable and backwards compatible platform – Windows.

#18 Yossi Kreinin on 06.10.14 at 8:41 am

Generics – a problem for some, not for me, hence not mentioned. Macros – might be a problem because there's no eval, either; I don't see it'd be a problem in my use cases at first glance, hence not mentioned.

REPL as a requirement – think Matlab. A Matlab user will kill you if you take his REPL. Python replaces Matlab for some, Go won't.

Scala is much too complicated for my taste (and it's "taste" and no other argument). Go vs Python is a common argument in part because they're both kinda simplistic – "similar philosophies" – so for me Go is a more likely alternative than Scala in that sense (if it weren't for the missing features). Maybe some day I'll get a feeling that I don't care about Scala's complexity as it won't "leak" out of the implementation into something I have to deal with…

Julia – a guy actually advocated to use it; I didn't jump on the idea, maybe wrongly… I think numpy for dump linear algebra problems is unbeatable, but for hairy stuff Julia might shine; Julia gaining momentum might be a very good thing for people needing this type of stuff – certainly "if it works" in the many relevant ways it has a good chance to beat Python convincingly as the generally better alternative.

Going to Go primarily because of the Python 2/3 clusterfuck is kinda crazy, much as I think 2/3 is a dumb fork.

#19 srathbun on 06.10.14 at 9:59 am

@CalebCushing

I wrote my code such that the sqlalchemy backend was independently importable to my ipython repl. That gave me access to all of my db stuff right there for testing out sql queries or seeing the results of function calls. Totally worth it for seeing what my program would be doing.

#20 smoe on 06.10.14 at 10:05 am

I'm not thinking of switching from Python to Go completely but experimenting with it for certain use cases.

For example in my current site project almost all of the logic is within background workers who scrape data, analyze and categorize it. The Public API is basically just doing fixed sql queries on that prepared data.
So I don't have any real benefits using a dynamic language like python.

I planned to use Scala first because it seems to be a better match with Python in machine learning projects, but the learning curve was too high for me and I didn't want to lose too much time.

#21 Mohamed on 06.10.14 at 12:13 pm

Funny how the article and most of the comments leaves the impression that adopting a language requires exclusivity. Projects define the language you need, not the opposite. Hell you can even combine many of them if you plan wisely and carefully to leverage the strength of each one of them. You don't have to give up on Python if you think Go fits best in a situation.

sorry for stating the evidence.

#22 Norman Yarvin on 06.10.14 at 9:26 pm

If you want to log the call stack in Go, there's a function in the "runtime" package that returns it.

But yes, you still need an if statement to check for errors when opening files; Go's designers want it that way. They think that using exceptions to handle such errors makes for confusing code, what with its action-at-a-distance behavior: you have an open call throwing an exception in one place, and it being handled in another, whereas with if statements the check is right after the open. Of course if you don't want to catch the exception, but just bomb out on failure, that criticism doesn't apply; in that case the if statement is just more boilerplate code that you wouldn't have to enter in a language where errors were delivered via exceptions.

#23 Dobrosław Żybort on 06.10.14 at 11:52 pm

"Because nobody is crazy enough to write web sites in C++ in the first place…"
There are even web frameworks in C++: CppCMS, Duda.io, Wt Web Toolkit, TreeFrog Framework

And you should check:
http://www.techempower.com/benchmarks/

#24 RickyS on 06.11.14 at 1:35 am

1. "Machine Learning" is a lot of things. Many of them process very large data sets, where interpreted languages don't shine.

2. What percentage of apps do Linear Algebra calculations?

3. Languages live and die by their libraries and library-like functionality. The Go system of packages makes building and using libraries very nice. But that's not enough of a reason to switch from Python.

4. Lots of business apps, online stores, multi-terminal customer support, automating chain stores, day-trading, calling taxis, discussion forums, and so on are server-like. They have a large number of people online and a series of servers at headquarters or in the cloud. Go does very well at that.

5. Go is easy to learn and to use, and for a lot of shops may be a very good 2nd language. Depending…

6. If you want numpy and repl, Go is not your language.

#25 Christian on 06.11.14 at 1:38 am

I've experience in Python, Go, and Java. I liked Go because of its simplicity, but then I learned that it is a bit too simple: no generics, no good mocking support, missing libraries, ugly builds with C dependencies, primitive doc format and so on. I felt a lot less productive than in Java.

I'd suggest to try Java 8 or Scala. You get a huge ecosystem, the best tools and good performance.

#26 RickyS on 06.11.14 at 4:18 am

If the only effect of Go was to replace and displace PHP, then Go is making a great service to humanity.

#27 Ccx on 06.12.14 at 2:47 am

>> Performance, static typing. But – again – if I needed that, I would have switched to Java from Python years before Go came along. Right? <<

These are the reasons I'm investigating OCaml right now. Similar internal design to python (GIL and all that), but funcional with data types inference so you won't get java-crazy. And compiles down to efficient native binaries. Julia is also tempting though, as is Mercury.

#28 Larry Clapp on 06.12.14 at 7:14 pm

I'm a Go aficionado who writes Perl during the day. And I would just like to say: Fair enough.

Not all languages are for everyone. I read Programming Python years ago and basically felt kind of "meh" at the end. If Go isn't your style, I'd be the first to say, Don't do that then.

I hear you on the REPL. I use zsh the same way. Some of my "one liners" get pre-tty long! And the Lisp REPL was nice when I was playing with Lisp.

That being said … fwiw I've found that TDD can help ameliorate the pain of not having a REPL. And there's "gore" (https://github.com/sriram-srinivasan/gore), which gives you the Read-Eval part (and print if you want to), just no loop, and thus no persistent state.

Thanks for the article. I enjoyed it.

#29 Alexandre Zani on 06.13.14 at 5:22 am

I can't believe that nobody mentioned go's compiler's confusion of lint errors with syntax errors. Try to write an expression, assign its result to a variable and compile to see if you made a mistake. Well, you did because you're not using that variable and god forbid that an unused variable ever make it into production. I don't know about others, but I'm constantly compiling half-baked code to help me catch stupid mistakes early and go makes that very difficult.

#30 Yossi Kreinin on 06.13.14 at 6:47 am

Actually I sorta did mention it in my REPL example, though this one was unused imports. But I'm a bit ambivalent on this one; I tend to compile with -Werror, sometimes with -Wno-unused and sometimes without. Unused variables can be bugs, on the other hand they very often crop up during development. The trouble is, it's not clear when to turn off -Wno-unused.

#31 Ivan Tikhonov on 06.13.14 at 7:03 am

There is at least G-WAN and Wt. So i assume at least some people do write websites in C/C++

#32 Alexandre Zani on 06.13.14 at 10:03 am

How you want to deal with that will depend a lot upon the system you are developing and your development infrastructure. But I think it's fairly easy to setup a pre-commit hook that will try to compile your binary with strict flags. (And run the fast part of your test suite while you're at it) Similarly, if you have a deployment "process", you can also build your binary with stricter flags there.

To be honest, that complaint is a big reason why I gave up on go. It slowed down my code-compile-run cycle in a very frustrating way. The fact that failed assertions in unit tests print no useful information is another reason.

#33 Jason on 06.15.14 at 2:02 pm

Alexandre: re tests giving little info: agreed. GoConvey fixes this for me.

#34 Jason on 06.15.14 at 2:09 pm

Yossi, I miss the repl too. I think it will happen for go by 1.4, or 1.5 at the latest. The only missing pieces to support a repl have already been done, they just aren't merged into the mainline release yet.

#35 Sebastien on 06.16.14 at 1:03 pm

wrt the repl…

There is github.com/sbinet/igo
which I salvaged from the go-1 clean up.
It's by no means complete but still useful at times.

When go will support shared libraries, imports would probably be easier to implement and provide.

#36 Yossi Kreinin on 06.28.14 at 10:18 am

test

#37 Johan Ouwerkerk on 07.03.14 at 4:05 am

As it happens your local Java implementations might well have the necessary hooks which let you do REPL stuff with it, based on the 'javax.script' framework. It allows you to run, for example a hosted Python interpreter in your Java application and/or call code across language boundaries.

So if you want the dynamic stuff back you can do that relatively straightforwardly: port the code for which performance matters to, say, Java and keep most everything else as a script.

#38 cmccabe on 07.05.14 at 10:57 am

It really comes down to using the right tool for the job. Engineering is all about tradeoffs, and there is no magic programming language which is optimal for every use-case.

It's nice to have eval(), because then you can have an interactive shell or a REPL. Creating certain forms of self-modifying code become easier. On the other hand, if you have an eval(), then you are vulnerable to various forms of malicious code injection, and it becomes harder to reason about what any given program will do. You also have a lot of deployment complexity when loading code dynamically. Just mention the word "classpath" to a Java devops engineer and watch their reaction. (Note that C/C++ style loadable modules are on the Golang roadmap, so it will at least have that soon.)

You can write shorter and more elegant code when using exceptions instead of return codes. On the other hand, it becomes more difficult to reason about what happens when there are failures. Suddenly every function has almost an infinite number of exit points. "finally" blocks and "catch" clauses can help, but only at the cost of introducing even more ugliness and verbosity than return codes.

Operator overloading makes matrix math look a lot nicer. And probably a lot of other mathematical notations. But suddenly, to quote your own essays about C++, you don't even know what code is executed by "a + b" any more. If you crash deep inside some operator code, the call stack will look like a dog's breakfast. And of course, operator overloading requires exceptions.

These are fundamental tradeoffs in programming language design. Golang chose to make tradeoffs that prioritize robustness, simplicity, and high performance for servers, at the cost of expressiveness, interactivity, and flexibility. It turns out that for a fairly large class of applications, Golang's choices are excellent. And that (combined with Google's clout) is why the language is seeing so much adoption.

Python chose to make tradeoffs that are good for scripting and perhaps good for doing some types of scientific computing (where you don't need low-level optimizations, or can rely on pre-constructed optimized libraries). The mass migration from Python to Go is not about scientific computing or scripting, but about people who are just finding that servers are a lot easier in Go. And that's fine. Python is going to keep on keeping on, and nobody will blame you for sticking around (but keep an eye on Julia and R, of course…)

I think you're absolutely right that Java is the closest competitor to Golang. But unfortunately, your post made almost no useful comparisons between Java and Golang. If you think that the threading model is the only thing different between Java and Golang, you're seriously mistaken. The whole type system is different in fundamental ways, the compilation model is different, error handling is different, the runtime is completely different, etc. etc. Goroutines and slices is just the tip of the iceberg. Don't take this the wrong way, but your offhand comment that with Java 8 plus a library or two, Java and Go will basically be the same really reveals that you need to do more research here.

Anyway, as always, a very thought-provoking post. I hope you get a chance to tinker with Go, Rust, and some of the other new languages at some point. It's definitely fun to try something new. And you just might learn about something that takes your mind off Java :)

#39 Yossi Kreinin on 07.05.14 at 4:47 pm

I didn't say they were the same; I think they're fairly different despite profound similarities in their marketing, many core features and even the bondage and discipline approach ("languages for someone else" – "they're not researchers, they're Googlers, people straight out of college" to quote Rob Pike; Java's and Go's compiler-error-based error handling approaches are actually not quite different…).

But looking at those differences, is Go better?

* Java is way more portable today

* Java's IDE support is almost certainly better

* Java's CPU performance is almost certainly better (http://benchmarksgame.alioth.debian.org/u32/benchmark.php?test=all&lang=go&lang2=java&data=u32)

* Perhaps most importantly for power users – hackability of Java/JVM almost certainly beats Go's; for instance what you called "a couple of libraries" involves pretty heavy metaprogramming where coroutines are added to Java:

"Of the three pieces, coroutines are the most challenging to implement on the JVM, as they require bytecode instrumentation. Essentially, every possibly-pausing method (the Quasar/Pulsar nomenclature is “suspendable”) must be inspected to find all invocations of other suspendable methods. Before the call to a suspendable method, code must be injected to push the caller’s local variables onto a stack object. Also, code must be injected to the beginning of every suspendable method, that upon resuming would jump to the instruction following the pause-point. This has to be done to all suspendable methods on the (OS thread) stack.

Fortunately, I found Matthias Mann’s continuations library that not only does exactly that and only that, but is also small, fast and easy to understand."

So Java doesn't have coroutines but JVM metaprogramming lets you add them. Could you add coroutines to Go if they didn't come baked in with any degree of portability and without hacking your compiler? My bet is you couldn't. Similarly, there's a ton of languages atop JVM which interoperate nicely with Java. I don't think it's nearly as easy with Go. (And I'm sure Go's non-OO type system, introduced with much fanfare and arrogance, doesn't make bindings to popular libraries any easier.)

As to things like $CLASSPATH – "it's complicated"; certainly static linking makes deployment easier – and it also makes fixing bugs harder (more binaries to recompile), it makes some sorts of debugging harder (think ltrace), etc. Certainly once Go adds support to dynamic loading it'll have all the problems – and advantages – of $CLASSPATH, $LD_LIBRARY_PATH, $PYTHONPATH or whatever it is your devops friends hate the most…

What is the awful thing Java has that Go doesn't? A culture of verbosity. This is the one thing that I find off-putting about Java and given Go's momentum if I were to write a highly concurrent server I might choose Go over Java.

That said, it would be better for everyone if "Go" was a set of Java libraries adding coroutines and maybe less verbose ways to do things. Go adds a huge amount of duplication (think all the library functionality implemented in Java as well as Go and umpteen other languages) and for this cost "society", this amorphous being that has no representative body but does exist, basically got coroutines and a select statement that could be done elsewhere perfectly well.

Of course knowing Go's authors noone would expect anything "less" than starting a new language… And it could be worse…

Did I do "enough research" on Go and Java? Perhaps not, and I'd be interested to hear more details about those things that Go does better.

As to Rust – Rust is nice, and Rust is not redundant. Rust might actually replace C++ for embedded type of work some day and I'm certainly following it with much anticipation. Incidentally, the vibe coming off Rust developers doesn't rub me the wrong way the way Go's echo chamber does. That despite Go being more of a "get shit done" culture which I tend to like, and the Rust culture being perhaps overly "thoughtful" to my taste.

#40 cmccabe on 07.16.14 at 12:24 am

Golang is portable to MacOS, the BSDs, Linux, and Windows. That covers pretty much all the platforms that matter for server code. There is ARM support for embedded systems as well. The Go guys have done a great job of being responsive to bug reports and feature requests on alternate platforms, and there is an active culture of go developers on Windows… probably to a larger extent than many of the other languages we're discussing here.

Just about the only important thing you can't run Go on is a microcontroller, but you can't run Java or Python there either, so this is a silly discussion. Go isn't available on iOS and Android either, but neither are most other languages, for completely non-technical reasons.

Your portability comment particularly rankles me because I've spent a lot of time re-implementing platform support that Sun left out of Java because of their "less is more" portability approach. For example, I implemented this code to fix the fact that they left out UNIX domain sockets:
https://svn.apache.org/repos/asf/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/unix/DomainSocket.java

The issue is that if there was a platform-specific feature that could not be supported on all platforms, Java just left it out. Sometimes those platform-specific features are crucial, though. For example, without UNIX domain sockets, you can't implement file descriptor passing, and a whole class of optimizations become impossible. Golang takes the more sensible approach of making all platform features available if you want them, but also making it possible to write portable code if you want that too. Java is starting to fix some of these bad portability decisions… slowly. But a lot of them still bite, if you use the language for real.

The IDE support comment seems very unfair. Golang is a statically typed language with an extremely easy-to-parse grammar. IDE support is simple to add, and a lot of people are doing so. IntelliJ / IDEA is probably the best option if you want something familiar. It is trivial to create a "smart" IDE for Go because all the type information is known at compile time and the syntax is regular and consistent. I can't say the same thing for C++ or Python, languages which will always have poor IDE support until we invent an IDE that can pass the Turing test.

Let's talk about coroutines for a moment. Java had coroutines in the past. In fact, coroutines were the first thing that Java had… in version 1.1, using OS-level threads was not even an option. http://en.wikipedia.org/wiki/Green_threads#Green_threads_in_the_Java_virtual_machine. People have added coroutines to all sorts of low-level languages. Here's an example of adding coroutines to C: http://dunkels.com/adam/pt/ .

What makes Go better is not that it has coroutines, but that they're so thoroughly integrated into the language. When you're choosing libraries, you don't need to worry about coroutine support… you know all the libraries will support it. You will never be able to say the same about C, C++, or Java. I've written a substantial amount of non-blocking code, even a non-blocking RPC system in C++. I know what it's like. Basically you are constantly hoping, pleading with the compiler that you won't call a function that will block the OS thread for a long period. And it sucks. And the language chooses intelligently how many OS-level threads to use, rather than making it your problem.

It's frustrating that you attribute Java's problems to "a culture of verbosity." There are fundamental reasons why Java is verbose, and they flow from the type system, not from "a culture" or individual bad programmers.
I wrote about this here: http://www.club.cc.cmu.edu/~cmccabe/blog_golang_type_system.html

> "As to things like $CLASSPATH – "it's complicated"; certainly
> static linking makes deployment easier – and it also makes fixing
> bugs harder (more binaries to recompile), it makes some sorts of
> debugging harder (think ltrace), etc"

If you try out Go, you'll quickly find that it has lightning-fast compile times, even for very large projects. This makes the need to recompile to fix a bug not very important. In general, I don't buy the argument that libraries allow quicker deployment to nodes than static binaries. Maybe libraries would allow you to push out 1 MB to all your nodes rather than 10 MB. Are you using networking hardware made in the last 10 years? If so, you shouldn't care about 1 MB versus 10. This is why Google links their C++ binaries statically. The company I work for does the same with our C++ binaries, to the extent that it's practical.

Libraries make debugging harder most of the time. Even getting a stack trace becomes a challenge, because you can't easily map addresses to function names (different loading point each time). And if you don't have the same library versions as the customer did when they experienced the problem, most of the time you can just forget about debugging library issues.

Loadable modules are absolutely not the same thing as CLASSPATH. CLASSPATH is mandatory, even for programs that never want to load anything dynamically. That's why every Java program has to come with a loathsome shell script to chaperone it around. This would all have been a little bit better if Java had established a C-style convention about where to find those JAR libraries for each application, but, well… they didn't. And every program chose a different convention, and a different shell script to set up that convention.

> "As to Rust – Rust is nice, and Rust is not redundant. Rust
> might actually replace C++ for embedded type of work some
> day and I'm certainly following it with much anticipation."

I think you are being really unfair to Go. I've written a lot of C++ and Java code, and a little bit of Go code, and I like what I found. There are tons of features that you don't even know about. For example, Go's lightning-fast build system that doesn't even rely on Makefiles / pom files / any kind of crusty build script. These guys learned the lessons of large-scale software development well.

I agree that Rust is promising, because of the ability to avoid garbage collection. But we need to reserve judgement on Rust until they actually declare the language stable and start building an ecosystem. Then we will see what falls out.

#41 cmccabe on 07.16.14 at 12:25 am

"And it sucks. And the language chooses intelligently how many OS-level threads to use, rather than making it your problem."

Er, that should read, "And it sucks. Whereas in Golang, the language chooses…"

#42 Yossi Kreinin on 07.16.14 at 8:36 pm

You know, it's sad how what I wrote reads to you. I'm thinking to maybe publish a followup post instead of a reply…

I do know about Go's fast builds, I didn't praise them because Python isn't lacking in that department; just like I didn't mention Go's lack of generics because Python doesn't have them, either (and I don't think it's such a crippling thing for the kinds of things I want to do, regardless of what others are doing.)

Maybe a followup post…

I never said Go wasn't a smart thing for Google to do, or that it's not a smart thing to do in a server. I only said that Go does nothing for me that Java didn't, that it's a lot like Java and implicitly I assumed in all that that a new language is a big cost for society and how wonderful it would be if Go "leveraged" (love the word) an existing language/VM instead of being its own language reimplementing endless library functionality and fragmenting the library base for all of humanity for what to me seems like insufficient reasons to do so. Maybe it's too much like wishing for world peace though… Java, C#, Go, Swift…

Maybe a followup post. I do have answers to your points but at a larger level it's sad that I come across to you the way I apparently do and maybe I could reexplain myself…

#43 cmccabe on 07.17.14 at 2:43 am

I think you made some valid points about Golang not replacing Python in all use cases. numpy is pretty cool. I actually open up an interactive Python shell whenever I need to do some moderately complex calculation, and I write scripts to generate graphs and so forth. numpy has some graph generation stuff which is awesome for putting together a presentation.

It would be nice to see a reasonably thorough comparison between Java and Go. Maybe someday I'll try to write one. I can't claim to be unbiased, but maybe I can claim to be "properly biased" by having used both languages for a while.

Re-using the JVM is a double-edged sword. You can get your language off the ground faster, and the JVM is pretty highly optimized. And you get the ability to link with a lot of existing software. In return you give up: the ability to allocate objects on the stack (all objects are allocated on the heap in the JVM, except primitives), the ability to efficiently implement a non-inheritance-based type model like Go's, and fast startup times. Fast startup times seem like a trivial thing, but when sysadmins start writing shell scripts to call a bunch of tools for your project, it doesn't seem so trivial. (We have a lot of people convinced that HDFS is super slow because they wrote a shell script to upload files in a loop, spawning a new JVM each time to upload each file. Yeah, these people are dumb but… can you blame them for wanting convenience?) Rob Pike has said that you might need to add new bytecodes to the JVM to efficiently support Go. The other big issue is that once you start linking to Java code directly, you can no longer assume that all the libraries you're calling support coroutines well– since you have to support calling any old crazy code that someone wrote in 1999 for JDK 1.0.

Looking forward to your followup. Your posts are always interesting and well thought-out, whether or not I agree.

#44 Yossi Kreinin on 07.17.14 at 8:55 am

Rob Pike discussed the option of "Go on the JVM"? Interesting!

#45 Eric P on 08.09.14 at 3:40 am

Since Groovy is a superset of Java you can use the Groovy Shell as a REPL for Java. Or you can use the Scala REPL though the syntax is somewhat different than Java – for basic expressions it doesn't matter.

#46 Michael on 11.08.14 at 5:58 am

I feel like this article was written just for me, but by the wrong person (due to your work being so different from mine). I'm that guy who writes the back-end for a fairly dynamic web app in Python. I've been trying to decide whether to really dive into Go for about 2 years now, and I think I will. The stumbling point for me all along has been exceptions. However, my coding style has evolved so much over the past couple years, and I find myself using exceptions (custom error classes, raising and handling errors as a mode of flattening control flow) as much as I used to.

#47 David on 12.05.14 at 6:40 am

Thanks for the article. I've been programming in Python for about 7 years off and on and recently picked up Go. I went through a pretty steep learning curve with Go's idioms but I'm getting there. For me, Python is still my goto language for devops and websites. Cheers

#48 j on 03.29.15 at 10:49 pm

WTF

#49 Luis on 12.21.15 at 8:26 pm

I wonder if it's feasible to create a pythonic transpiler for Go. Something like CoffeeScript, that would bring list comprehension and other goodies to Go, while enjoying its better performance and concurrency.

#50 Meh on 01.24.16 at 10:27 pm

Your points are just flamatory insults to GO, the problem with Python is its meant to be C like which still requires C to handle the heavy lifting. It's more glue code than actual scripting, GO was designed to be small and simple its basically a better C. Yes that means you don't have access to a massive maths library or even the ability to do OOP in GO but then again you couldn't do that in C either. GO is much faster than both Python and Java because its compiled to exe or binary, if that isn't enough of a justification to use a systems language I don't know what is. You want real power try assembly.

#51 Raphael Herouart on 02.05.19 at 3:03 pm

How do you plan to implement eval() in a compiled language?

In JVM/.NET languages, user executing the program is required to have the VM/ framework on his machine. Same for interpreters.

How do you do:

eval(string_from_user_or_file); // example: "x++"

?

Go delivers compiled code. A bunch of bytes respecting the ABI of the operating systems on top of which it is running. The "x" name in the original source is only an unnamed memory location in the compiled executable.

For similar reasons an REPL on a compiled language would need to be completely independent fro the Go compiler, and hence have separate maintenance for every new feature/release.

#52 savannah Cats 22 on 03.26.19 at 11:37 pm

Remarkable! Its truly remarkable paragraph, I have got much clear idea on the topic of from
this article.

#53 MIAMI STOP FITNESs on 04.06.19 at 1:49 pm

Thanks for your personal marvelous posting!

I actually enjoyed reading it, you're a great author. I will always bookmark
your blog and will come back sometime soon. I want to encourage you continue your great job, have a nice day!

#54 Shad on 04.07.19 at 9:19 am

Thanks for the auspicious writeup. It if truth be told used to be a enjoyment
account it. Glance advanced to far delivered agreeable from you!
However, how could we be in contact?

#55 Mint ToursSnowboard Tours on 04.08.19 at 12:59 am

Yes! Finally someone writes about NZ snow tour.

#56 WEST lAKE EYES on 04.09.19 at 4:05 pm

You've made some really good points there. I checked
on the net for more info about the issue and found most people will go along
with your views on this website.

#57 sarasota moving companies on 04.15.19 at 4:38 pm

When someone writes an article he/she keeps the idea of a user in his/her brain that how a user can understand it.
Thus that's why this piece of writing is perfect.
Thanks!

#58 Siecor Corning TKT-UNICAM on 04.16.19 at 1:33 am

Right now it sounds like Expression Engine is the preferred blogging platform available right now.

(from what I've read) Is that what you're using on your blog?

#59 HD1 on 04.18.19 at 6:58 am

Thanks for sharing your thoughts on Power Quality Recorders.
Regards

#60 DMC5 on 04.24.19 at 8:52 am

This is a really good tip especially to those new to the blogosphere. Short but very accurate information… Thanks for sharing this one. A must read article!

#61 Buy Leica ScanStation P16 on 04.28.19 at 1:42 pm

It's amazing designed for me to have a web page, which is useful in favor of my knowledge.
thanks admin

#62 professional movers com on 05.06.19 at 2:23 am

Wow that was strange. I just wrote an very long
comment but after I clicked submit my comment didn't appear.
Grrrr… well I'm not writing all that over
again. Anyway, just wanted to say wonderful blog!

#63 T41 Spec Sheet on 05.06.19 at 6:20 am

Appreciate the recommendation. Will try
it out.

#64 ScanStation C5 Software on 05.07.19 at 1:12 pm

You can definitely see your expertise within the work you write.
The world hopes for even more passionate writers like you who
are not afraid to say how they believe. Always go after your heart.

#65 Apex Legends on 05.15.19 at 1:14 am

This site truly has all of the information I wanted about this subject and didn’t know who to ask.

#66 battlefield 1 esp on 05.15.19 at 10:48 pm

I consider something really special in this site.

#67 Shavonda Pietz on 05.16.19 at 3:55 pm

Like the site– extremely user-friendly and lots to see!

#68 Probiotics for adults on 05.26.19 at 3:36 am

Hello my friend! I wish to say that this article is awesome,
great written and come with approximately all vital infos.
I'd like to look more posts like this .

#69 www.astrumhelicopters.com on 06.01.19 at 11:26 pm

I enjoy reading an article that can make men and women think.

Also, many thanks for permitting me to comment!

#70 covet fashion hack 2019 no human verification on 06.06.19 at 5:40 pm

Thanks for discussing your ideas. I'd personally also like to express that video games have been ever evolving. Modern tools and improvements have made it simpler to create practical and active games. These entertainment games were not as sensible when the real concept was being tried. Just like other designs of technological know-how, video games also have had to progress by many years. This is testimony towards fast progression of video games.

#71 토토솔루션임대 on 06.06.19 at 8:17 pm

Yes! Finally someone writes about 토토솔루션분양.

#72 토토사이트 졸업 on 06.10.19 at 11:11 pm

Howdy! I simply would like to offer you a huge thumbs up for
your great information you've got right here on this post.
I am returning to your blog for more soon.

#73 안전놀이터 사설배팅 on 06.11.19 at 2:19 pm

Thanks to my father who stated to me about this blog, this webpage is
truly remarkable.

#74 토토사이트 on 06.13.19 at 3:48 pm

Please let me know if you're looking for a author for your site.
You have some really great posts and I believe I would be a good asset.

If you ever want to take some of the load off, I'd love to write some material for your blog in exchange for a link back to mine.
Please shoot me an email if interested. Many thanks!

#75 vn hax pubg on 06.17.19 at 6:49 pm

Hey, happy that i stumble on this in bing. Thanks!

#76 먹튀검증 사이트 on 06.18.19 at 3:53 am

Admiring the dedication you put into your website and in depth information you present.
It's great to come across a blog every once in a while that isn't the same old rehashed information.
Wonderful read! I've saved your site and I'm including your RSS feeds to my Google account.

#77 proxo key generator on 06.19.19 at 4:12 pm

Cheers, i really think i will be back to your page

#78 effective marketing strategies on 06.20.19 at 10:50 am

Aw, this was a really good post. Spending some time and actual effort to create a superb article… but what can I say… I procrastinate a lot and never seem to get nearly anything done.

#79 vn hax download on 06.21.19 at 12:39 am

Good Morning, bing lead me here, keep up great work.

#80 poseidonhd on 06.21.19 at 7:41 am

You can certainly see your skills within the article
you write. The sector hopes for even more passionate writers such as you who aren't afraid to mention how they believe.
All the time go after your heart.

#81 poseidon hd on 06.21.19 at 7:47 am

I every time used to study piece of writing in news papers but now
as I am a user of internet thus from now I am using net for
articles or reviews, thanks to web.

#82 nonsense diamond on 06.21.19 at 1:44 pm

Some truly interesting article on this web site , appreciate it for contribution.

#83 game of dice cheats on 06.23.19 at 10:55 pm

Thank You for this.

#84 web design Manchester on 06.24.19 at 1:56 pm

Wow, fantastic blog layout! How long have you been blogging
for? you made blogging look easy. The overall look
of your website is great, let alone the content!

#85 gx tool pro apk download on 06.24.19 at 8:44 pm

Good Morning, happy that i stumble on this in bing. Thanks!

#86 qureka pro apk on 06.26.19 at 1:35 am

I must say, as a lot as I enjoyed reading what you had to say, I couldnt help but lose interest after a while.

#87 krunker aimbot on 06.26.19 at 11:52 am

This does interest me

#88 cbd edibles uk on 06.27.19 at 5:18 pm

I got this website from my pal who told me about this web site
and now this time I am browsing this site and reading very informative content at this time.

#89 plus size skater dress on 06.28.19 at 3:19 am

This design is incredible! You certainly know how to keep a reader
entertained. Between your wit and your videos, I
was almost moved to start my own blog (well,
almost…HaHa!) Wonderful job. I really loved what you had to say, and more than that,
how you presented it. Too cool!

#90 mariouhuiv.fitnell.com on 06.28.19 at 2:12 pm

Hello, Neat post. There's an issue along with your site in web explorer, might test this?
IE nonetheless is the market leader and a good section of other people will omit your magnificent writing because of this problem.

#91 http://consultor-seo59360.blogkoo.com/ on 06.30.19 at 4:29 pm

Hello! This is my first visit to your blog! We are a team of volunteers
and starting a new project in a community in the same niche.

Your blog provided us valuable information to work on. You have done a wonderful job!

#92 메이저사이트 on 07.04.19 at 3:56 pm

Hi, yup this article is really nice and I have learned lot of things
from it regarding blogging. thanks.

#93 Hye on 07.05.19 at 2:35 am

It's the best time to make some plans for the future
and it's time to be happy. I've read this post and if I could I desire to suggest you some interesting things or tips.
Perhaps you can write next articles referring to this article.
I desire to read more things about it!

#94 buy hemp seeds on 07.05.19 at 12:33 pm

This article will assist the internet people for building up new blog or even a blog from start to
end.

#95 locksmith near me on 07.05.19 at 11:14 pm

What's up, after reading this awesome piece of writing i am as well delighted
to share my knowledge here with mates.

#96 http://consultor-de-seo85060.bluxeblog.com/ on 07.06.19 at 1:18 pm

I don't even know how I ended up here, but I thought this post was good.

I do not know who you are but definitely you're going to a
famous blogger if you are not already ;) Cheers!

#97 ufc 3 pc skidrow on 07.06.19 at 2:49 pm

Good, this is what I was looking for in bing

#98 http://www.ebaystores.com/youngessential/_i.html?rt=nc&_sid=1797557094&_trksid=p4634.c0.m14&_sop=10&_sc=1 on 07.07.19 at 1:03 am

Heya! I'm at work surfing around your blog from my new
iphone! Just wanted to say I love reading through your blog and look forward to all your posts!

Carry on the outstanding work!

#99 spyhunter 5.4.2.101 crack on 07.08.19 at 3:04 pm

Hello, bing lead me here, keep up great work.

#100 fps unlocker download on 07.09.19 at 5:11 pm

This helps. Thanks!

#101 josuegathv.onesmablog.com on 07.10.19 at 3:32 pm

Great article! That is the kind of info that are supposed
to be shared across the web. Shame on the search engines for no longer
positioning this submit higher! Come on over and consult with my web
site . Thank you =)

#102 Rosie on 07.12.19 at 12:01 am

I always emailed this weblog post page to all my contacts, for the reason that if like to
read it next my contacts will too.

#103 Hot Offer In Bangladesh on 07.12.19 at 10:51 am

For most up-to-date information you have to pay a quick visit world-wide-web and on internet I found this site as a best website for latest updates.

#104 Marilou on 07.12.19 at 1:32 pm

Thankfulness to my father who told me about this web
site, this website is really remarkable.

#105 homeschooling in pa on 07.13.19 at 10:44 pm

At this time I am going to do my breakfast, after having my
breakfast coming again to read additional news.

#106 alessandra_jane on 07.14.19 at 1:59 am

Thank you for the great read!

#107 ASUS GT501 TUF Intel on 07.14.19 at 11:25 pm

Hi, i think that i saw you visited my site so i came to “return the favor”.I am attempting to find
things to improve my website!I suppose its ok to use a few of your ideas!!

#108 online porn cam on 07.15.19 at 2:10 am

some great ideas this gave me!

#109 Blanca on 07.15.19 at 12:35 pm

You ought to take part in a contest for one of the most useful
websites on the web. I am going to highly recommend this site!

#110 롤강의 on 07.15.19 at 1:21 pm

For newest news you have to visit the web and on world-wide-web
I found this website as a finest web page for
latest updates.

#111 legalporn on 07.15.19 at 11:54 pm

great advice you give

#112 legal porno on 07.16.19 at 12:34 am

great advice you give

#113 Depresión on 07.17.19 at 12:54 pm

Good way of describing, and nice post to get data on the topic of my presentation topic, which i am
going to present in university.

#114 Alfonzo Cahela on 07.18.19 at 2:31 am

Dreamwalker, this code is your next piece of data. Please contact the agency at your convenience. No further information until next transmission. This is broadcast #7163. Do not delete.

#115 Sara on 07.18.19 at 5:12 am

Valuable info. Lucky me I discovered your website by accident, and I am shocked
why this coincidence didn't took place in advance! I bookmarked
it.

#116 nana_garnet on 07.19.19 at 1:43 am

you are amazing

#117 jazzy on 07.19.19 at 2:12 am

you are so great

#118 buydrugonline on 07.19.19 at 2:49 am

This blog is amazing! Thank you.

#119 Buy Drugs Online on 07.19.19 at 3:06 am

This blog is amazing! Thank you.

#120 corpouraba.gov.co on 07.20.19 at 12:07 am

Do you have a spam problem on this site; I also am a blogger, and I was curious about your
situation; many of us have created some nice methods and
we are looking to trade methods with other folks, be sure to shoot me an e-mail if interested.

#121 Connie Pille on 07.20.19 at 7:08 am

Very, very pleased.

#122 비아그라 on 07.21.19 at 10:33 pm

whoah this blog is excellent i really like studying your posts.
Stay up the good work! You already know, many individuals are looking
round for this information, you can aid them greatly.

#123 jaipur tourist taxi service on 07.22.19 at 2:41 am

It is not my first time to go to see this website, i am browsing this
web page dailly and take good data from here everyday.

#124 laser hair removal new york on 07.22.19 at 1:10 pm

What a material of un-ambiguity and preserveness of valuable know-how on the topic
of unexpected emotions.

#125 bpkb mobil on 07.22.19 at 11:06 pm

Everything is very open with a precise explanation of the issues.
It was truly informative. Your website is very useful. Thank you for sharing!

#126 http://holdenvlzsm.articlesblogger.com/ on 07.23.19 at 7:46 am

Good information. Lucky me I found your site by chance (stumbleupon).
I have book marked it for later!

#127 Ivey on 07.23.19 at 3:28 pm

I'm not sure the place you are getting your information, however great topic.
I must spend some time finding out much more or working out more.
Thanks for wonderful information I used to be searching for this information for my mission.

#128 Pay Loans Online on 07.23.19 at 4:27 pm

Appreciate this post. Will try it out.

#129 consultoria-seo93704.aioblogs.com on 07.23.19 at 4:42 pm

I do not even know how I ended up here, but I thought this post was good.
I don't know who you are but definitely you are going to a famous blogger if you aren't
already ;) Cheers!

#130 evogame.net/wifi on 07.23.19 at 7:31 pm

Your post has proven useful to me.

#131 date coufgar on 07.23.19 at 10:39 pm

I am 43 years old and a mother this helped me!

#132 descargar peliculas on 07.23.19 at 10:47 pm

Hi it's me, I am also visiting this site daily, this web
site is genuinely good and the people are actually sharing good thoughts.

#133 adte cougar on 07.23.19 at 10:58 pm

I am 43 years old and a mother this helped me!

#134 date coubgar on 07.23.19 at 11:37 pm

I am 43 years old and a mother this helped me!

#135 date cougaer on 07.23.19 at 11:42 pm

I am 43 years old and a mother this helped me!

#136 dahe cougar on 07.23.19 at 11:59 pm

I am 43 years old and a mother this helped me!

#137 forza horizon 4 keygen on 07.24.19 at 7:43 pm

Found this on MSN and I’m happy I did. Well written website.

#138 campsites near Swakopmund on 07.25.19 at 2:01 pm

It's a pity you don't have a donate button! I'd most certainly donate to this outstanding blog!
I guess for now i'll settle for book-marking and adding your RSS feed to my Google account.
I look forward to fresh updates and will share
this website with my Facebook group. Chat soon!

#139 guest farms near Swakopmund on 07.25.19 at 3:21 pm

What you said was actually very logical. But, what about this?
what if you were to create a killer title?

I am not saying your content is not solid., but what if you added a headline to maybe grab folk's attention? I mean Things from
Python I'd miss in Go is kinda plain. You could
peek at Yahoo's home page and note how they write post headlines to get people to open the links.
You might add a related video or a related pic or two to grab people excited about everything've written. In my opinion, it would make your blog a little
bit more interesting.

#140 ezfrags on 07.25.19 at 10:43 pm

I like this page, because so much useful stuff on here : D.

#141 skisploit on 07.27.19 at 12:00 am

Your website has proven useful to me.

#142 Emma on 07.27.19 at 2:59 am

It's the best time to make some plans for the future and it is
time to be happy. I've read this post and if I could I wish to suggest
you some interesting things or tips. Maybe you can write next
articles referring to this article. I want to read even more things about it!

#143 matte lipstick facestockholm.com on 07.27.19 at 3:40 am

My developer is trying to persuade me to move to .net from PHP.
I have always disliked the idea because of the expenses.
But he's tryiong none the less. I've been using WordPress
on various websites for about a year and am nervous about switching to another
platform. I have heard fantastic things about blogengine.net.
Is there a way I can import all my wordpress content into it?
Any help would be greatly appreciated!

#144 Daniela on 07.27.19 at 7:14 pm

Hi! Quick question that's completely off topic.
Do you know how to make your site mobile friendly? My website looks weird when browsing from my iphone 4.

I'm trying to find a theme or plugin that might be able to fix this problem.
If you have any suggestions, please share. With thanks!

#145 jaredukfvj.bloginwi.com on 07.28.19 at 3:20 am

Hi there every one, here every one is sharing these know-how, thus it's
nice to read this weblog, and I used to visit this website daily.

#146 hunting in Namibia on 07.28.19 at 2:29 pm

I was wondering if you ever thought of changing the structure of
your blog? Its very well written; I love what youve got to say.

But maybe you could a little more in the way of
content so people could connect with it better. Youve got an awful lot of text for
only having one or 2 pictures. Maybe you could space it out better?

#147 read books online on 07.28.19 at 5:07 pm

Howdy! This post couldn't be written much better! Looking through this
article reminds me of my previous roommate! He always kept preaching
about this. I will forward this information to him.

Fairly certain he will have a good read. I appreciate you for
sharing!

#148 DEALS AND OFFERS WEBSITES on 07.28.19 at 5:33 pm

Why viewers still make use of to read news papers when in this technological world the whole thing is
available on web?

#149 totoyoinfo on 08.21.19 at 1:10 pm

토파더는 다양한 스포츠 게임을 즐길 수 있는 메이저 안전놀이터이며, 100% 먹튀검증된 사이트를 제공합니다.

#150 totofather on 08.21.19 at 1:11 pm

토토요는 토토,파워볼을 위한 메이저사이트를 제공합니다. 토토사이트에 대해 100% 먹튀검증되어 신뢰할 수 있는 안전놀이터를 제공합니다.