I mean that the compiler does not check if I’m handling the error. I can easily just ignore the error and work with the value, and therefore have code that breaks if the value might not be there.
Any code that compiles should not be able to ever segfault or have NullPointerExceptions or similar.
To interface via an FFI with a game engine, which uses a custom allocator, and you need to pass datatypes between it and your own code?
(As I’ve done in Java!)
To replace existing implementations with your own, because you want a LinkedArrayList (a linked list of blocks)? Or because you want a TreeMap instead of a HashMap, or a Set with different implementation?
This is an interesting point actually. Because it gets raised every time and I actually thought the same before starting with Go.
Thing is, in practice you usually don't need special generic containers. And when I actually need it, I'll just code up a non-generic implementation. When I need a complex type system I'll use Scala.
Well, I use them a lot – I’ve written lots and lots of generic code in my projects, and reuse it across many dozens of projects.
This allows me to have fully reactive collections in Java, lazy reactive collections, and more.
I can just connect to a socket transmitting updates with netty, write a transformer, apply those to a lazy reactive collection, and have the changes directly appear in the list in the UI, fully threadsafe.
Writing those things again, and again, every time, would be far more work, and increase the time I need to write code massively.
I’ve actually used go a bit, and tried reimplementing several of my projects in go, but either it wasn’t easily possible, or I had to translate dozens of generic classes into hundreds of non-generic versions, with lots of duplicated code.
And then I had found a bug, fixed it at one point, and had to copy it to hundreds of files.
Currently not, as I only used it in smaller projects in the past.
In the future I’ll use it likely with QuasselDroid-NG, an app of mine that’s very early in development, and for which I developed it.
The use case there is that we have a list of IRC messages, constantly updating and adding messages at any point of the list, and we want to update the UI and animate.
The client can also cache, or preload, messages at any point, or throw them away.
Additionally, users can filter, search, or choose to disable some messages.
Other messages might get merged, or synthetic ones inserted.
So I have a backing store of messages that can constantly change, I have on top of that a stream of transformations taking part, and on top of that an interface presenting a single, consistent Java List, but also triggering the relevant updates on Android’s recyclerview.
Most importantly, you can just add a message to the lowest list, it will be properly filtered, transformed, animated, and displayed, and this properly threadsafe across UI thread, backend thread, and filtering threadpool, while being faster than the solutions Realms and co provide for such updated UI.
Well, I don't see any problems with the logic part. Receiving, filtering, transforming, and notifying someone else about incoming messages (would probably do it in a few threads, sending messages between each other).
For the UI part: no wonder, Go, at least currently, is useless for UI's.
> (would probably do it in a few threads, sending messages between each other).
The problem is that I try to abstract these things away – in Java, I have a general framework, and just do
var c = new ObservableCollection<Message>();
var f = new AsyncObservableFilter<Message>();
f.setSource(c);
f.addFilter(new DayChangeMessageFilter());
f.addFilter(new CollapseJoinLeaveMessageFilter());
f.addFilter(new RemoveIgnoredMessagesFilter());
var adapter = new ObservableAdapter<Message, MessageViewHolder>();
adapter.setCollection(f.getResultCollection());
and then I can do
c.add(new Message(new Date(), "cube2222", "Well, I don't see any problems with the logic part."));
And this works for any type – I can use the same code for observable collections of IRC networks, of channels, etc. And I do use them for that. And if I change the filters, it also does the minimum amount of work necessary to update the list, and not a single CPU cycle more.
I’m using it with over 11 different types in the Java version, and I’d have to maintain 11 identical, but with different types, versions in the Go version.
You can understand how much of a pain in the ass this is.
Oh, btw, this also abstracts away the entire thread handling, while still doing it in a reasonable way.
And the backing collection doesn’t have to be a normal ObservableCollection storing data in memory – I also have ones using SQLite as backend, or caches, and I have the ability to add listeners for scrolling up or down to load or unload data as well, if it’s not needed anymore.
In Go, I’d manually have to reify all these, and if I find a bug in one, I’d have to update all of the others, too.
Of course I can't say for 100% as I don't know your codebase. But I think you could easily do this with Message being an interface defining the common functionality of your messages (like, probably, render(), timestamp(), id()). Then you could just have you DayChangeFilter use the timestamp, joinleave do a type assertion, removeignored check for the id.
If the genericism for you is also abstracting away the source of the messages -> in Go you just usually abstract sources as io.Readers.
All filters can easily be an intermediate channel which only sends further proper messages. Or just write a filter(func (m Message) bool) function which abstracts that away.
Though I understand you may want to use your Reactive collections and streams, this isn't really a case for Go.
Ok sorry, I thought the unit of generic'ness you mean is the message. You're basically just talking about generic custom collections. Yeah, it is a thing you won't get in Go. And you'll have to write it every time again.
I'm usually just writing custom ones for each case, takes just a little bit more work. If I need more genericness, as I said, I use Java/Scala/F#
EDIT: In theory you can hack this all together using interface{}, but I wouldn't do that, it's a hack and ignores the type safety of the language.
What do you mean with no compiler safety exactly?