Hacker Newsnew | past | comments | ask | show | jobs | submit | hepta's commentslogin

Doesn't seem like valid JS, you wouldn't need mark.js if that were the case.


Yes you would. JSON is valid JS, and executing JSON in a browser is a recipe for disaster.


JSON isn’t valid JS – its representation of strings allows U+2028 and U+2029 to appear unescaped, but JavaScript string literals don’t.

Not sure how else executing (valid) JSON in a browser would be a recipe for disaster? `eval` was the standard way to parse JSON from trusted sources for a long time.


I do agree that there are problems where the "maps of facts" approach is better suited than ADTs. I'm not sure if those are the majority of problems we're solving. You can still do all that in a typed language, using dictionaries. You can be as precise as you want. In some sense you lose that without a type-checker.

I only have my experience (which is about 1/4 of his) to lean on. And I've only had problems when protocols are not well understood by all parties, never the opposite. Talking in the level of ADTs (or some representation that is equally precise) tends to either clear things up, or uncover problems that were not obvious in informal discussion.


> Talking in the level of ADTs (or some representation that is equally precise)

I will argue that ADTs offer no more precision than first-class properties and first-class properties are much more aligned with human beings natural way of thinking.

I.e., "name" is semantically strong/precise, I don't need to enslave it to a Person class. I can give a Cat a name, a building a name, etc.

ADTs are trying to bundle properties together when those properties should/could have strong enough semantics on their own and be much more "composable" (RH's term) and freer to use.


Maybe we have to dig into the specifics: there's a lot of things that can be done with Name, regardless of where the name belongs, is that what you mean? If so, most typed languages let you say that Person can be a thing with a Name. I don't have Clojure experience so we might be talking past each other here.


What resonates most with me is that traditionally ADTs make the properties second-class citizen to the ADT/class.

First-class properties are strong enough semantics and bundling them together in an ADT is almost always introducing coupling and rigidity with no real benefit.

Why do we need the Person class? Why do we need to taxonomize like that? The answer is we don't. All the Person class brings to the table is straight-jacketing and a false sense of order and security.


I haven't watched the full video, but here are some things that a hypothetical Person class brings to the table that you might be missing:

1) A Person class can guarantee that a Person can not exist unless it is fully specified. E.g. you prevent Persons from being created that don't have a date of birth.

2) A Person class provides a syntactically nice place to put pieces of code that rely on the instance fields. E.g. a function like Person(...).computeAge(DateTime.now)

3) A Person class can be a nice place to put inter-field validations. E.g. Maybe you don't want to allow Persons to be constructed if their last name is the same as their first name

4) A Person class can bring clarity to function signatures that depend on it. Basically resolving the problems that Duck-typing introduces


What's a "first-class property"?


   class Person {
      def age;
   }
There is a second-class "age" property: the only way to specify it or use it is to first declare the ADT/Person class. (In this example, I use a dynamic language; that is, the property can be given any type of value.)

Here is the usage of a first-class age property:

   public boolean isOld(Map<String, Object> entity) {
      return entity.getAs("age", int.class) > 30;
   }
Note that in this example, age's semantics are independent of any Person/ADT. Now a statically-typed language that would let me define a vocabulary that include "age" and its type independent of an ADT would be supporting first-class properties.

I could cheat and do this in a typed language like Java like so:

   class Age { int val; } // using class to define a property
   class Entity { Age age; ...and list all other properties here... }
But this is absurdly cumbersome and obviously Java isn't conducive to this.


> Note that in this example, age's semantics are independent of any Person/ADT. Now a statically-typed language that would let me define a vocabulary that include "age" and its type independent of an ADT would be supporting first-class properties.

What you're referring to is known as row polymorphism or structural typing and it exists in languages such as Elm, Purescript, Scala and Go (and I believe Haskell has these as an extension). For instance, this is valid Scala:

    def isOld(thing: {def age: Int}): Boolean =
      thing.age > 30

    case class Person(name: String, age: Int)
    case class Dog(age: Int)
    println(isOld(Person("Jim", 25))
    println(isOld(Dog(31))
And here's Elm:

    isOld : {age: Int | a} -> Bool
    isOld thing = thing.age > 30

    Debug.log (isOld {name: "Jim", age: 42})
    Debug.log (isOld {age: 10})


This is pretty cool. The Scala version is a little weird. Why do I need a separate Person and Dog class? Can't a dog have a name as well? Why do I need to declare that upfront or ensure that no other part of code can give a Dog a name? That's the problem with ADTs; there's all this impedance.

The Elm version is much better. Except of course I have to upfront at the method signature declare my property requirements -- while that is also a burden, it is a much lesser burden than having ADT/taxonomy of Person, Dog, etc.


I think the Scala version does exactly what you want it to do, but you seem to be confused about something that I can't really pin-point.

> Why do I need a separate Person and Dog class?

You don't. It's an example.

> Can't a dog have a name as well?

It can.

> Why do I need to declare that upfront or ensure that no other part of code can give a Dog a name?

I have trouble understanding the meaning of that sentence.


> The Elm version is much better. Except of course I have to upfront at the method signature declare my property requirements -- while that is also a burden, it is a much lesser burden than having ADT/taxonomy of Person, Dog, etc.

Elm (and Purescript) should be able to fully infer the type of that function w/o forcing you to declare which fields you want to use up-front.


How would it infer:

   isOld(parseJson(json))
When parseJson may or may not produce an entity with the "age" property?


Sorry, I wasn't clear. My point was that you don't have to declare the type of `thing` up front in that example. It would be able to infer that it's a record with an `age` field from the function's definition.

In your example, `parseJson` would have to return a record with an age field, otherwise the compiler would complain. Personally, I think that represents a reasonable tradeoff in ease of use for safety.


> I believe Haskell has these as an extension

Not really ... Haskell has libraries that claim to implement this but we Haskellers have to admit Haskell's support for row types is pretty poor. A Clojurist's objections to Haskell on those grounds are valid (in practice though not in theory).


Does this meet your criteria of "first-class" property? It works on any entity that "has" and "age", at least according to my definition of those things!

    -- The class definition can often be entirely elided
    -- with Generics or Template Haskell.  Instance   
    -- definitions can generally require minimal or no
    -- implementation either
    class HasAge r age | r -> age where
        getAge :: r -> age
        setAge :: r -> age -> r
    
    isOld :: HasAge r => r -> Bool
    isOld r = getAge r > 30


Firs-class generally means something you can put in a variable and compose with higher order operations. Think first class functions.


> I do agree that there are problems where the "maps of facts" approach is better suited than ADTs. I'm not sure if those are the majority of problems we're solving.

This also seems like the kind of thing where row-types would allow for statically typed, fully inferred programs that are written in the style Rich is advocating.


There is code that doesn't `constantly cast ti and from Object`, most code won't need to, anyway. Generic information is kept during type-checking and then is discarded, this can be considered an optimization. There are some warts that appear because of erasure, but I believe you're wrong in implying that most developers care (most java developers, maybe scala peole have more issues because of erasure).


> The only down side is removed compatibility with other languages like C and C++ and C#, locking in the app to a specific language more.

Using a Stream instead of a for loop does very little to make your code incompatible with C. It is already pretty much incompatible (modulo JNI).

What I mean is: if you want something that looks like C just use that, there is no gain in not learning new constructs just because older languages did not have them.


I imagine there is a way to raise a cow for beef that I find ethical. I don't know if you can do so for dairy cows. As far as I know, the cow has to have young to lactate, meaning it must be impregnated frequently. Am I wrong?

This is in constrast with chicken eggs, which I believe can be ethically produced (even though they aren't in the large majority of the industry).


Yeah, I'd like to know what the experience is for people who use it regularly.


I already use vavr, sadly such pattern matching is not exhaustive, which is the most important feature for me.


I think both are not exhaustive (or don't have exhaustiveness enforced by the compiler).


This seems like nitpicking as well. If the intention is that everything is an expression (that seems to be it, to me) then you have to have a Unit, no mater what you call it. I'd rather have a name that 3 academics know than override a distinct concept (Void) or make something entirely new.


What are your problems with spring boot? What bloat are you referring to?


I suppose most of my negative experiences with it are specifically in the context of using it to build microservices. The memory usage alone created a bit of a problem, I ended up using nearly all of my 16GB of RAM when I had to run many services simultaneously. And because the functionality of any given service was fairly minimal, there really wasn't a need for a framework like that.

The autoconfiguratuon was also a bit dangerous. Since any dependency could cause any other dependency to reconfigure itself, it made it difficult to determine why things would break at times. At one point one of our libraries that used RabbitMQ behaved differently in some other services because another dependency saw RabbitMQ on the class path and started trying to use queues that didn't exist. Someone spent a day and a half figuring that out because the error was being swallowed by something else so the application was just failing to start with some crypic error. And when autoconfiguration wasn't enough, you'd sometimes find yourself needing to write dozens of lines of Java to do something as simple as connecting to a second database.

In general I found we tended to have less predictable or obvious behavior in our Spring apps, and they tended to be more likely to fail at runtime than I would've liked.


I usually get rid of @EnableAutoConfiguration and then selectively import the auto-configuration classes I actually want with @ImportAutoConfiguration.


A Spring developer once mentioned, on a mailing list post i have long since lost, that the autoconfiguration stuff is pretty much demo-ware. It's good for getting a simple app up and running fast, but for anything serious, you should import the configurations manually, exactly as you say. Fortunately, that's an easy enough transition to make at any point in a project's lifetime.


I don't think I'll be working with it again in the near future but I'll definitely have to keep that in mind in the future.


For me, I imagine the dropwizard guys sat round asking each other what the best servlet container is, web MVC tool, ORM, DI framework, etc, etc. and they choose the very best they can think of for a dev to work with.

Then a couple of years later that company comes along where they ask the same questions and but there's a guy with Tourette's in the corner and Every. Single. Time. the answer to the question is SPRING!! SPRING!! SPRING'S THE RIGHT ANSWER!! SPRING!

From the moment you boot spring boot and discover how much longer it takes to boot it's a struggle not to question the motivations of a place where the answer's the same no matter the question.

Sorry. I know some people love it!


Actually, in that company, the answer isn't always Spring Boot. Sometimes it's Cloud Foundry.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: