It's time for this terrible "Objects in the large, functions in the small" idea to be put to bed.
FP can do side-effects, asynchrony etc just fine, it's just about controlling them so you can still reason about your program and compose its elements easily.
Kay-style message-sending object graphs are neither modular nor composable; state & effects leak transitively by observation, and they cannot be recombined in self-similar patterns. Local reasoning is impossible.
We can talk about specific situations where say, Actors models might have pros and cons, but a blanket recommendation that "it's probably time for an object layer" is rubbish.
Why not design for composability and modularity top to bottom?
I went into more verbal detail in the actual presentation; the argument is something like:
1) Programming is maths
2) Programming is about abstraction and finding patterns
3) CT describes abstract patterns in maths, and is therefore directly applicable to everyday programming.
4) (Exposition of Categories, Functors, Monoids)
5) Comparison of the mathematical concepts to equivalent programming concepts
6) Composability is a huge advantage for software in the large and the small; categories and monoids capture the essence of composable patterns.
7) Abstraction is hugely important for software; it allows to only know what we need, and no more. Category Theory gives us deeper, and dare I say, simpler abstractions. We can find underlying patterns and commonalities that we might have missed otherwise.
Firstly, thanks for all your great stuff on Math/Programming, it's been a great source of inspiration!
I would have liked to include Universal Properties, but I decided it was just too much to grasp for one session.
The audience were professional programmers, so there was a strong underlying message of "this is directly applicable to what you do". UMPs have got something important to say about abstraction -- what it means to have only what you need and no more. It just would have popped heads by the time I'd built up to it.
The vast differences between software and buildings correspond to the vast differences in designing them.
In context here, "minute detail" is obviously a relative term comparing the requirements of software and architecture design.
You just made up the "specific language" thing. The reason we don't get unicorns to write software for us is they don't exist either.
There are many incompetent software devs out there, but I don't see how anyone can possibly build any amount of software _well_ without having an appreciation of how to design it. This is why I used the word "capable".
The thing is, even if some of these things were similar to architecture, it would be by accident. They are, on the surface, totally different fields. On a deeper level, they're still totally different. The onus is on you to show the linkage, if you believe it to be applicable.
There's certainly great value in reading application source code, but it has nothing to do with physical Architecture. I do wish people would let go of this tired and completely wrong metaphor.
"Weak" and "strong" are not well-defined terms, and you'll find different defs around the place.
I deliberately used "weak" in the title as a loose umbrella term for the sundry malpractices detailed below. The article is hopefully otherwise quite specific.
In particular, by "types", I always mean "static types" or "propositions". What you mean mean by "dynamic types", I call "tags"; they are not the topic of the article. These usages are standard, if not universally adhered to; I hope I made this clear in the article.
Hi Manicdee! The point is that with any unityped representation you can come up with, the name tells you nothing certain; any conclusions you think you can draw from it are pixie-dust and moonshine. Even with nonsense names, the argument and return types give you solid proof not only about what the method does, but importantly what it _doesn't_ do.
There's no criticism implied of my colleagues at all -- I'm as culpable as anyone. The point is though, we can make big improvements with types, without paying a big cost.
A superset of ... what the? Why do you keep trotting out this garbage thread after thread?
Every language takes influences from others, if that's what you meant. Scala is influenced by Java, C# and Haskell, in that order. Kotlin is influenced by Scala and Java, etc.
The "superset" and "Lisp, Haskell and Javascript in the same compiler" comments are unhinged from the reality of any language I recognise.
There's a lot of "seems" going around from people who haven't used the language, or dynamic-typing folk who obviously aren't going to pick a language that bets the farm on static types.
As a long-time Java dev myself, Scala is solving problems you don't even realise you have, because you don't know to look for them.
Powerful types, immutable state and FP make a world of difference for writing clear solutions, with better abstractions, less code, less bugs and less bullshit than the horrendous status quo of corporate Java development.
While you can make do with either, they have complementary strengths and weaknesses, which are useful in different situations. See "Expression Problem", and "Visitor Pattern".
> Why not?
"Single Dispatch Polymorphism" is a language feature. ADTs/pattern matching are a language feature. Subtyping is a type-system feature. "Structural Typing" is a type-system feature. Guaranteeing exhaustive pattern matching is a type-system feature. They are not "type systems", and different languages pick them and combine them a la carte.
> But case classes cannot be part of an inheritance hierarchy nor structural types (or inheritance types) be used as ADTs
Yes they can, and they do. You just can't extend case classes from other case classes. You can use any class as an ADT-like structure if you want, leaving the hierarchy open or closed, and defining pattern matching extractors as you please. It's all part of the same system; whether you call it an "ADT" or a "class hierarchy" is a design pattern thing more than a rigid systemic property.
> Obviously, and that is why some languages employ the one or the other
Er... that doesn't follow. What I said is that it's very useful having both together. If you don't think that's valuable, that's fine; Scala's not for you.
You ran with this "three complete type systems" line in the last thread, and it's still totally wrong.
ADTs/pattern matching are not "a complete type system". Structural types are not "a complete type system". Scala unifies the different concepts by expressing them through Java-style classes and inheritance.
Even if they were incompatible non-orthogonal type systems sitting side by side (they aren't), it is immensely useful to have both dynamic dispatch and ADTs/pattern matching in the toolset; they are often useful for different problems.
Erk, no it isn't. If your semantics require an optional value, then encode it that way explicitly. Don't inflict special cases and bugs on everyone else.
FP can do side-effects, asynchrony etc just fine, it's just about controlling them so you can still reason about your program and compose its elements easily.
Kay-style message-sending object graphs are neither modular nor composable; state & effects leak transitively by observation, and they cannot be recombined in self-similar patterns. Local reasoning is impossible.
We can talk about specific situations where say, Actors models might have pros and cons, but a blanket recommendation that "it's probably time for an object layer" is rubbish.
Why not design for composability and modularity top to bottom?