That the first thing to build is trust. The disease that plagues companies is not communicating out of fear you'll get in trouble if something is broken or didn't get done. Build trust to counteract fear.
Why we still use HTTP is beyond me. And I don't mean about the speed issues. Why have a protocol that's so complicated when most of the things we need to build with it are either simpler or reimplement parts of the protocol.
Could you elaborate your issues with HTTP a bit? What kind of protocol would do a better job?
Minimal implementations of HTTP (and I'm strictly talking about the transport protocol, not about HTML, JS, ...) is dead simple and relatively easy to implement.
Of course there's a ton of extensions (gzip compression, keepalive, chunks, websockets, ...), but if you simply need to 'add HTTP' to one of your projects (and for some reason none of the existing libraries can be used) it shouldn't take too many lines of code until you can serve a simple 'hello world' site.
On top of all that, it's dead simple to put any one of the many existing reverse proxies/load balancers in front of your custom HTTP server to add load balancing, authentication, rate limiting (and all of those can be done in a standard way)
Furthermore, HTTP has the huge advantage of being readily available on pretty much every piece of hardware that has even the slightest idea of networking.
Any new technology would have to fight a steep uphill battle to convince existing users to switch.
I do see a lot of application protocols tunnelled over HTTP that have no sane reason to be. Partly to work around terrible firewalls/routers/etc. - but of course the willingness to work around those perpetuates their existence. E.g. one reason for the rise of Skype was so many crappy routers that couldn't handle SIP.
My friend once mentioned that FTP would be a good option, I'm not sure why though. I think they regarded HTTP as superfluous for the purpose of what we use the web for.
It's not just firewalls. The fact that (unencrypted) FTP is still widely used today when better alternatives like SFTP (via SSH) have existed for years strikes me as odd.
(I'm speaking about authenticated connections. For anonymous access - which should be read-only anyway - you're usually better off using HTTP anyway)
I once had to provide an FTP-like interface to user directories for the website's users. Couldn't find an easy way to do it with SFTP without creating Linux users. Found an FTPS daemon that would let me call an external script for auth and set a root directory, which made it trivial (once I deciphered its slightly-cryptic docs).
So in that case, at least, I was very glad FTP(S) was still around.
HTTP tends to be faster for what we use the web for: [0]
FTP does have some advantages, but HTTP has more advanced support for resuming connections, virtual hosting, better compression, and persistent connections, to name a few.
I bet if we had used FTP instead of HTTP for serving HTML right from the start, FTP would today have all of the same extensions and the same people would argue for it being too bloated :) (HTTP started as pretty minimalistic protocol back in the day)
I often find the discrepancy between what HTTP has originally been designed for (serving static HTML pages) and all the different things it's being used for today highly amusing. Yes, some of todays applications for HTTP border on abuse, but its versatility (combined with its simplicity) fascinates me.
No, because FTP is stateful, thus it sould not have scaled well to many HTTP usecases of today, and something alse would have been born probably, to solve the problems with statelessness, which can be solved by statelessness.
The two success factors of http are statelessness and fixed verbs.
HTTP is quite a good protocol. Simple, extensible to a sane extent, but not overly extensible (XMPP i'm thinking about you).
HTTP is not accidentally successful. FTP is a bad joke. (stateful. binary mode, 7 bit by default. uses multiple connections (unless in passive mode))
Basic http is dead simple, it works, and it also has many addons with backward compatibility (one can still use a basic http client or server in most cases) and even new version fully optimized to nowadays needs (and even in binary form)
A bunch of newline, (CRLF), seperated key-value mappings. Some with a DSL (Such as Set-Cookie).
It gives you a status message instantly, a date to check against cache, a Content-Type for your parser, acceptable encoding, for your parser, a bunch of other values for your cache. All for free.
As for the body of the content? For a gzipped value like this, it's everything outside the header, until EOF. That's not quite as easy as when the content-length parameter is given, but hardly difficult for parsing.
HTTP is easy.
In fact, HTTP is so easy, that in-complete HTTP servers can still serve up real content, and browsers can still read it.
HTTPS is more complicated, but if you simply rely on certificate stores and CAs, it becomes much easier, but HTTPS is a different protocol.
> As for the body of the content? For a gzipped value like this, it's everything outside the header, until EOF. That's not quite as easy as when the content-length parameter is given, but hardly difficult for parsing.
This is chunked and keep-
alive. Things get a little trickier
True, you keep the connection open, and receive a length of expected bytes, and then said bytes, until 0 is sent. Still simple enough that there are a dozen implementations of less than a page, only a search away.
> So what doesn’t a startup need to succeed, but an established company would consider an important requirement.
> The first is a fully-distributed, incremental capability for quickly and consistently backing up and restoring large databases using configurable storage sinks (e.g. S3 or GCS). The same functionality, but non-distributed, will be available for free to all users.
I appreciate that you're trying to write a good database and build a business, but what do you mean by "startup"?
If a database can't guarantee it can make backups, why would a startup attempt to use it in the first place?
(Cockroach Labs CTO here) This could have been worded more clearly in the post. There will be two versions of backup functionality: a basic implementation for free (Apache license) and a faster distributed and incremental implementation as a paid feature (CCL). It's like the difference between mysqldump and an InnoDB-aware backup tool.
Sounds like crippleware for a distributed database.
If you can't incrementally back it up, you can't really afford to run it in production in a cluster that has a large dataset. If you don't have a large dataset, you don't need cockroach db (first law of distributed objects, etc).
Maybe you'd be better off designing features for clients with specific requirements and very deep pockets.
Not necessarily, even small datasets can benefit from a distributed database. Configuring a HA database setup for any of the open source DB's requires a lot of work. For a startup, a small cluster can provide HA, redundancy, and ease of scalability should the need arise.
No one cares about the difference between 99.9 and 99.999 reliability at the DB layer and then adopts a new open source DB to solve that problem. Especially when that exciting, new, experimental database cripples your ability to back it up. Hilarious.
Is there a reason you're calling your non-free product something with "Community" in the name? CDB is intriguing but this feels like intentional doublethink to me.
I'd say "yes". But generally you don't have to (except in edge cases), library authors do. You benefit from stronger type guarantees.
It's a bit easier to think about it as ">=T" vs "<=T" though.
In one direction, you allow T and any subclass. This is probably the most common - all T subclasses should act like T, e.g. have method x() on them. You can assign a T subclass to a T variable or return it from a T-returning method. When you add something to a List<T>, it could be a T subclass, because it's "at least a T". (covariant)
In the other direction, you allow T and any superclass. My main way to think of this is for a callback, e.g. for declaring a `map` operation. If you're mapping over List<T>, you can't declare your callback as accepting a subclass of T because the list only contains "at least T". But you can accept a superclass (e.g. Object), because any T (or subclass) has that superclass. (contravariant)
---
If you don't have support for contravariance, you either give up flexibility (you can't make a reusable Object mapper) or safety (you can't guarantee the supplied callback is safe to call).
If there's no type hierarchy whatsoever, then you don't get the benefits of polymorphism. Which is the case in some languages - for those, you typically get looser call semantics (no checks, or duck typing or something) or forcing you to use e.g. match statements everywhere to do the same thing in N branches when you have N types in a list.
With functions and a type hierarchy of some kind (or implicit conversions, or whatever) you have the same kind of issues. When you declare the type of your map function (explicitly or implicitly) you're still bounded by the type you're mapping over. If you make a "(float x, returns float) x + 1e10" function, you can't use it to map over a list of doubles, because they can't be safely reduced in precision. The reverse works though, because floats can be promoted to doubles safely. You essentially have "double" as a subclass of "float". Whether it's OO or not has nothing to do with type hierarchies, OO just embraces them with reckless abandon.
Good type inference systems can hide a lot of this from you, allowing you to drop types most of the time and let the compiler specialize it / make sure it's safe to do this particular thing. But they can fail. When they do, how do you ensure safety?
Learning the term before the concept is putting the cart before the horse. But once you find yourself dealing with the fact that e.g. one can use a Source[Float] as a Source[Number] and not vice versa, whereas one can use a Sink[Number] as a Sink[Float] but not vice versa; one can use a Function[Number, Float] as a Function[Float, Float] or a Function[Number, Number] and either of those as a Function[Float, Number], but not in reverse, then it's useful to have words for these relationships so that we can talk about them.
I'd say "yes" only because this concept will exist whether or not you have a name for it. And it's a concept you will bump into in any language with any sort of generics (even Go [1])
I wrote Scala for the last 2 years and was the resident type system "expert", so I had to explain variance to people pretty often. Luckily, it's a pretty quick, mathy definition:
Some notation first:
A <: B means "A is a subtype of B"
A >: B means "A is a supertype of B"
F[_] refers to a unary type constructor.
Now for the definitions:
If F[_] is "covariant", it means that if A <: B, then F[A] <: F[B]
If F[_] is "contravariant", it means that if A >: B, then F[B] <: F[A]
Examples of covariant type constructors are List and Functions in their output. An example of a contravariant type constructor is Functions in their input type.
^ This is all that needs to be said! I can write it on a whiteboard in ~5 minutes. I'd say that's a reasonable thing to be expected to learn.
i think the way you defined it, covariant and contravariant are identical; in your contravariant definition, swap the names of "A" and "B" and you get:
if B >: A, then F[A] <: F[B]
and B >: A means the same as A <: B, so this means:
if A <: B, then F[A] <: F[B]
which is the same as your covariant definition.
Perhaps you meant:
If F[_] is "contravariant", it means that if A <: B, then F[B] <: F[A]
?
It's only meaningful if you are using a language that has static types, subtyping, and generics. That covers Java, C#, and Dart, but omits Ruby (no static types), SML (no subtyping), and Go (no generics), for example.
If you are a language where it matters, it comes in handy, even though you usually aren't aware of it. You probably already have a correct intuition of it without realizing it.
Say you have a class like:
class Enclosure<T> {
void cage(T item) { ... }
}
And assume some sort of class hierarchy like "Mammal is a subclass of Animal". If you have a method like:
The method expects an Enclosure<Mammal> and we're giving it an Enclosure<Animal>. Is that allowed? You probably intuitively see that it should be — an Enclosure<Animal> can hold any kind of animal and mammals are all animals. Your intuition is right.
"Contravariance" is the term to describe precisely what that intuition represents.
The data structures in Clojure are built on shallow 32-way trees. When you "change" a map or a vector, the algorithm only copies from the root node down to the parent of the leaf you're changing. That's log32(N) copied nodes in a tree of N nodes total.
Basically, yes. You can do more with a dynamic type system than a static type system because you don’t need to (and actually, aren’t allowed to) prove that your code is consistent. Advancements in static checking and inference mean you can prove more things about your programs, so you don’t have to fall back on dynamic types and data structures so much.
The quality of a type system isn't measured solely by what it allows you to do. After all, no type system at all would allow you to do anything and write as many bugs as you want-- not great, right? Instead, a better type system will let you make guarantees about your code, while still allowing correct programs to run. Can you guarantee there are no type errors? Can you guarantee arrays aren't accessed out of bounds? That sort of thing.
Well, you could look at a dynamic type system as just a static type system with 1 type—a sum type of everything. Looking at it that way, a dynamic type system is much less powerful.