Coming back to this ... and sorry no time to construct a blog too rushed ...To summarize ideas against premature specialization (not claiming these are original ideas):1. Don't use subclassing, i.e. don't implement any method in a supertype (e.g. `trait`) that isn't `final`, thus all methods are final (closed) in their existential type[1].2. Subtyping should only be injected locally at the call site with inversion-of-control (c.f. my ideas upthread for potential new forms of compiler assistance), or globally due to the Liskov Substitution Principle resulting from type constructors of kind >= 0 (a.k.a. type parametrization) and first-class functions (a.k.a. functional programming, i.e. functions can evaluate and return functions).3. Functional programming is differentiated from imperative programming in that the semantics are expressed more unified (atomically, i.e. higher-level) — of which premature specialization employing discarded semantics[2] (which includes unrolling function recursion replaced with loops and mutable variables), mutable variables[3], or referential opaqueness are egregious cases. Category theory can raise this up another level.Several resources[1][4] seems to confirm the criticism that Scala while being high-level, introduces more complexity than Haskell.Most of the aforementioned premature specializations Haskell makes difficult to introduce (which the Scala programmer could choose to avoid but isn't discouraged from doing so), except apparently Haskell can't do the implicit global subtyping due to LSP (in #2)—such as adding elements of different types to a list—because refinement types are impossible due to bottom populating all types, i.e. Haskell can't do the new injunction and disjunction types of the DOT calculus (Dotty)![5]
Except apparently the lack of subtyping (refinement types) in Haskell is a major weakness (even after we remove subclassing, which is an anti-pattern) which means DOT (Dotty) could potentially take a big leap ahead? Is this paucity the price paid for Haskell's revered brevity?"5. It should have a rich type structure that permits introduction of new abstract types and which supports modular program development. By giving short shrift to expressions and evaluation, imperative language have an impoverished notion of type—and not support for modularity. Worse, object-oriented programming, a species of imperative programming, is fundamentally antimodular because of the absurd emphasis on inheritance and the reliance on class-based organizations in which functionality metastasizes throughout a program.""Scala also has the ability to namespace a function by giving special status to one of its arguments (some people call this OO, then don’t, in the very next breath – I never get it). What I mean is, you may have two functions with the same name, which are disambiguated at the call site by the type of the argument to the left of the dot. I am deliberately not calling this by any special name, but rather focussing on its utility – Haskell can do this with qualified imports – not quite so nice. I am usually, though not always, particularly unimaginative when it comes to inventing function names – allowing me to reuse one without a penalty is very handy indeed. Note here I do not mean overloading – I think the Scala community has worked out that overloading is just not worth it – do not do it, ever.""I must associate a provenance with that bit in order to give it meaning. “This bit being true means that e and e’ are equal, whereas this other bit being false means that some other two expressions are not equal.” Keeping track of this information (or attempting to recover it using any number of program analysis techniques) is notoriously difficult. The only thing you can do with a bit is to branch on it, and pretty soon you’re lost in a thicket of if-the-else’s, and you lose track of what’s what. Evolve the program a little, and you’re soon out to sea, and find yourself in need of sat solvers to figure out what the hell is going on.""It’s just that Boolean thinking has infected the software world to such an extent that I feel that I have to fight back. Just the idea of comparison to “null” to obtain a Boolean is absurd, even if you think you need a “null” pointer (which you don’t, in a properly designed language).""2. It should support both computation by evaluation and computation by execution. Evaluation is a smooth generalization of high school- and university-level mathematics, and is defined in terms of standard mathematical concepts such as tuples, functions, numbers, and so forth. Variables are given meaning by substitution, and evaluation consists of simplifying expressions. Execution is the action of a program on another agent or data structure conceived of as existing independently of the program itself. The data lives “over there” and the program “over here” diddles that data. Assignables (my word for what in imperative languges are wrongly called variables) are given meaning by get and put operations (fetch and store), not by substitution. Execution consists of performing these operations."http://joshbassett.info/2013/hello-haskell-goodbye-scala/"These tools exist and are as useful as they are, because of certain fundamental properties of Haskell itself. Here I mean, the hoogle function is only as useful as it is because Haskell tags IO effects in the type delineating values with types IO t and t, so hoogling for say, [a] -> Int eliminates a lot of candidate functions that would have this type in other environments. In Scala, without the delineation between an Int that has been computed with its arguments, and an Int that has been computed with the entire universe, a hoogle-equivalent would not be as useful"
Thinking about how this relates to the problem of loss of specialization (restriction) due to inheritance subsumption:Afaics, the generalized, paradigmatic solution to the above linked problem is:List[+A] {def contains[B <: A](x: B)(implicit areEqual: (A, B) => Bool): Bool}where inheritance is not used for the types of A and B. For example, a Number can implement a Ordered and an OrderedDivisable typeclass (which can be tested with an implicit input parameter), but it doesn't inherit from those interfaces. Whereas, the type of A is covariant so that we may assign return values of type List[T] which BTW should be intersections of types in the container instead of a subsumption of types in the container (as is now the case in Scala 2.11).Again it would be ideal if the future compiler would automatically create the apropos areEqual with the requisite match-case boilerplate to extract the types from the intersection and call the extant instances of areEqual for each type in the intersection.In other words, it appears the intersection and union types of DOT are essential to play correctly with forsaking premature restriction via premature inheritance of types. Inheritance should only come into play where it is unavoidable due to Liskov Substitution Principle and therein the compiler should automatically do the match-case boilerplate for us.Thoughts please?On Tuesday, June 16, 2015 at 9:00:25 AM UTC+8, Shelby wrote:On further thought, why can't the future compiler expand that boilerplate for us, even the match-case boilerplate (done at caller site thus VM type erasure is irrelevant) where T is an intersection types that each have an implementation of Desired[_] available in the current scope, so then we only need to write:def f[T](a: List[T])(implicit b: Desired[T])Or better yet the sugar where the compiler does the boilerplate internal to the function too:def f(a: List[Desired])It seems Haskell has modularity correct with typeclasses instead of inheritance?
On Tuesday, June 16, 2015 at 7:49:11 AM UTC+8, Shelby wrote:def f[T](a: List[T], b: Desired[T]) ...I note that the Dotty Dependent Object Types calculus is orthogonal to mixin inheritance modeling because of the potential for overlapping premature specialization. Also I note that typeclasses are nearly a complete solution to the Expression Problem and I do not recall which of the "issues" (are even really issues?) I had enumerated are due to the typeclass pattern and/or the coinductive type system of Haskell (where _|_ is the Top type, not Bottom as in an inductive language such as Scala):(luckily I was able to capture the above document from a google cache after stackoverflow deleted it)A typeclass in Scala appears to me to just be a way of specifying an interface that many types can implement (and types can implement more than one interface without conflating them with their existential type) and then providing an implicit function to automatically inject them into the context where they are used:But as noted in my linked document above, automatic injection for Haskell doesn't play well with containers and perhaps inheritance (although perhaps that is due to other factors such as the coinductive type system).Thus it appears to me that explicit injection via functional programming is the most modular. Is the reason I find Haskell so confusing is because it is obscuring the boilerplate in invisible implicit typing?Did we somehow lose the plot along the way with Scala and the concept of merging functional with object oriented programming?I don't know the answer to that question, but here is one rabbit hole I found:My current thinking (subject to change as I learn more) is the Scala roadmap towards Dependent Object Types is appropriate because it simplifies to intersections and unions of types, which appears to me to be an unavoidable consequence of covariant and contravariant container cases. I am not clear how much of the rest of Scala is not more harmful than needed?If the basic syntax and compiler could be radically simplified (thus hopefully must faster too), perhaps this could make Scala more appealing to a wider audience and use-cases[1]. Conceptually for the separation-of-concerns perhaps the other "features" could be done with macros operating on the AST. Appears by not modeling inheritance in DOT, this may be the conceptional direction being toyed with?I am trying to wrap my head around what would be the idea language for programming the "web 4.0" which I visualize as unification of app programming and server programming[1]. It should be light weight, because one thing that drives many startups away from Java is the heaviness of the toolset and learning curve as compared to Javascript.P.S. there may a lot (≈$millions) of money available to throw at this, if someone can elucidate the issues and optimal direction succinctly.On Tuesday, May 12, 2015 at 4:22:59 PM UTC+8, martin wrote:So, putting types in traits can be a
premature restriction of their usage.
The alternative to cakes is essentially functional abstraction. Have
components parameterized by others.--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
I remember Adriaan Moors' explanation that in the DOT calculus a disjunction of types contains the conjunction of methods of those types (and shared methods input a DISJUNCTION of the inputs of those methods) and conversely a conjunction of types contains the disjunction of methods of those types (and shared methods input a CONJUNCTION of the inputs of those methods).
On Wed, Jul 22, 2015, 11:52 AM Shelby <she...@coolpage.com> wrote:
I hate mailing lists; there is no edit feature.
That's another advantage of using a blog...
Have you considered hosting a blog on github pages? It's not that hard.
Edits are in CAPS...
On Wednesday, July 22, 2015 at 11:47:04 PM UTC+8, Shelby wrote:
I remember Adriaan Moors' explanation that in the DOT calculus a disjunction of types contains the conjunction of methods of those types (and shared methods input a DISJUNCTION of the inputs of those methods) and conversely a conjunction of types contains the disjunction of methods of those types (and shared methods input a CONJUNCTION of the inputs of those methods).
On Wed, Jul 22, 2015, 11:47 AM Shelby <she...@coolpage.com> wrote:
Are readers able to see the post I made on July 18 which starts with following? When viewing this thread in Google Groups, it appears to have inserted [scala-language]" into the subject line causing the start of a new thread (and other mangling of my post).
> I believe I show herein the fundamental importance of objects (as in "OOP"), that subclassing (but not subtyping)
> is fundamentally an anti-pattern, and that the new DOT calculus is essential.
Hi Vlad,
Covariance: a set of types (whether represented as a subsumption to a nominal supertype or the supertype which is a disjunction of the nominal types) can be operated on by a function which inputs that subsumption (or the set of the corresponding supersumption) or outputs the set of that subsumption (or the corresponding supersumption).
Contravariance: a set of types (whether represented as a supersumption to a nominal subtype, e.g. _|_ aka Bottom/Nothing, or the subtype which is a conjunction of the nominal types) can be operated on by a function which inputs that supersumption (or the set of the corresponding subsumption) or outputs the set of that supersumption (or the corresponding subsumption).
But how can we do any operations on a conjunction of types?
I remember Adriaan Moors explanation that in the DOT calculus a disjunction of types contains the conjunction of
methods
I believe the plan was changed later.
Have you tried using dotty?
of those types (and shared methods input a conjunction of the inputs of those methods) and conversely a conjunction of types contains the disjunction of methods of those types (and shared methods input a disjunction of the inputs of those methods).
If a set of types share a set of methods (perhaps implemented as typeclass rather than virtual inheritance so the dictionary can be injected with an object), then the disjunction of those types is the conjunction (and the conjunction of those types is the disjunction) of the implementations of that interface. But note that A ∧ A = A ∨ A, so thus both disjunction and conjunction can be operated upon if they share an interface A.
That was the point of my prior post.
How does your point relate to mine?
On Sunday, July 19, 2015 at 4:17:38 AM UTC+8, Vlad Patryshev wrote:
I would not seriously involve LSP into solving this kind of problems. LSP is for explaining things to beginners, not for solving problems in "applied category theory" (as some people call programming these days).
One of the solutions is to think about a natural transformation from a covariant functor to a contravariant functor (List[+T] => List[-T]).
Thanks,
-Vlad
Also I discovered this interesting presentation from Martin Odersky contrasting ML modules and Scala's abstract and self types and the Cake pattern:
http://stackoverflow.com/questions/15584848/whats-the-difference-if-any-between-standard-mls-module-system-and-ocaml-mod#comment22427900_15585373
If by "type of discussion" you mean the topic, this is a good forum to discuss it. However, while I can't speak for anyone else, I can't contribute to a discussion that I can't follow. So either you're way beyond me, and i
If by "type of discussion" you mean the topic, this is a good forum to discuss it. However, while I can't speak for anyone else, I can't contribute to a discussion that I can't follow. So either you're way beyond me, and i
don't know how many other people, so you may need to find individuals that are interested in and up to the discussion; or it's just the way you write that's hard for me to follow, which may be due to things like unfamiliar words and the length of each email. Also it seems like you often revise your emails. So maybe it would be a good idea to first write on a blog, leaving yourself the time to edit it to your satisfaction, and once that's done, and you want to discuss it, figure out how to boil it down to something much more digestible on a mailing list.Just my two cents, and again I'm not speaking for anyone else.
... because I am concerned that DOT and Dotty need some radical tweak yet before we go that direction. All the progress is great, but I think by not discarding subclassing and replacing it with my proposal for compiler assisted inversion-of-control (assuming it can't be otherwise unified from some other perspective such as category theory), then we will have lost a critical opportunity to be the next mainstream language that overtakes Java finally.
I recently watched the video of Martin's presentation from Scaladays 2015 and I really love the TASTY direction to modularize orthogonal compilation layers. Kudos!
And I love the conceptual idea of simplification via unification (paradigm shift) in DOT. I just think we will miss a huge opportunity if we don't deprecate subclassing for Scala 3. If we look at the popular languages, it is Java #1 but on a steady decline (perhaps Android and Java 8 staved off a free fall for a short while) and all these FP languages as nipping at its heels, e.g. Scala, Clojure, Python, etc..
Scala needs to be cleaned up and even less verbose. Eliminating subclassing can enable the DOT calculus to become much simpler and also enable more opportunities to infer types to reduce verbosity.
IMO what has prevented an FP language from overtaking Java is the lack of mainstream need for any particular feature of FP, as well as it being presented a bit too obtusely. Scala made some leaps forward on being less obtuse because it looks more like a familiar OOP language, eager evaluation by default, non-total by default, etc.. But the most salient point IMHO, is there is no requirement to use typing in programming. People can make arguments either for and against static typing.
But I think I have shown (and I understand I need to organize my presentation and thoughts soon) that no one can get fine grained extensibility (that is without refactoring and recompilation) without my idea for inversion-of-control which requires the sophisticated and unified typing of DOT (sans the subclassing).
On Fri, Aug 21, 2015, 5:03 PM Shelby <she...@coolpage.com> wrote:
I have two reasons to sort of break my implied promise in my prior message that I would come back when organized.
1. I have been in an ongoing discussion with a senior software developer as follows below, who is an expert Java programmer, who favors Lisp as his favorite language, and who a polygot in computer languages. So the following summary may need to be revised on further clarifications from that person. But I think it will remain true that it serves as a poignant insight into why Scala can never become a mainstream
language
Wait, it hasn't already?
This might be worth a read:
http://codahale.com/the-rest-of-the-story/
http://codahale.com/downloads/email-to-donald.txt
Having worked with Scala; I'd say I love it.
Having worked with Scala; I'd say don't use it for most projects.
It is not the best language to start learning FP. Wrap your head around a dedicated FP language and if you still feel the need for a hybrid FP/OO language Scala is definitely worth a look.
However as it is a hybrid I've felt it made my code just too complex. Compared to Java there are a dozen more ways in Scala to fix something; and often you struggle to find the best way. This takes a lot of learning and it just isn't worth it. It's a great and elegant language in many ways, but I've come to dislike a lot of features of it.
Simplicity is one of those things that make a beautiful codebase. See also (recently featured on HN)
# let distance (x1,y1) (x2,y2) =
sqrt ((x1 -. x2) ** 2. +. (y1 -. y2) ** 2.)
So in Scala:
def distance((x1,y1), (x2,y2)) = ...
And why can't Scala infer those types given sqrt inputs Float? One of the big complaints I hear is Scala can't infer types.
Or at least why do I have to redeclare the types in a class that implements a trait where the types where already declared in the trait and there is no ambiguity?
P.S. in our second post you pointed out that a function with more than one parameter is a unary function under application and a function with more than two parameters is an infix function under application, so I need to think about how that meshes with my idea about only allowing unary and infix functions to use spaces instead of parens.
One issue I see with obligatory (versus optional) named parameters, is I really wish Scala could do OCaml's (tuple and any other unapply) destructing on the function parameters:
# let distance (x1,y1) (x2,y2) = sqrt ((x1 -. x2) ** 2. +. (y1 -. y2) ** 2.) So in Scala: def distance((x1,y1), (x2,y2)) = ... And why can't Scala infer those types given sqrt inputs Float? One of the big complaints I hear is Scala can't infer types.
This is a complaint
mostly by Haskell people or people doing lots of functional
programming in general. Beside from a few cases I don't see this
as very important. You don't want to have inferred argument
types in public methods for any nontrivial project.
Or at least why do I have to redeclare the types in a class that implements a trait where the types where already declared in the trait and there is no ambiguity?
You don't have to:
On 08/23/2015 09:05 PM, Shelby wrote:
One issue I see with obligatory (versus optional) named parameters, is I really wish Scala could do OCaml's (tuple and any other unapply) destructing on the function parameters:
# let distance (x1,y1) (x2,y2) = sqrt ((x1 -. x2) ** 2. +. (y1 -. y2) ** 2.) So in Scala: def distance((x1,y1), (x2,y2)) = ... And why can't Scala infer those types given sqrt inputs Float? One of the big complaints I hear is Scala can't infer types.
This is a complaint mostly by Haskell people or people doing lots of functional programming in general. Beside from a few cases I don't see this as very important. You don't want to have inferred argument types in public methods for any nontrivial project.
Or at least why do I have to redeclare the types in a class that implements a trait where the types where already declared in the trait and there is no ambiguity?
You don't have to:
% s -Yinfer-argument-types
Welcome to Scala version 2.11.7 (OpenJDK 64-Bit Server VM, Java 1.7.0_85).
Type in expressions to have them evaluated.
Type :help for more information.
scala> trait T { def f(i: Int) = i }
defined trait T
scala> trait TT extends T { override def f(i) = i }
defined trait TT
<rant>Of the many things I hate about OCaml's syntax is that it does everything snobbishly different from C, C++, Java heritage of the mainstream, e.g. semicolons as separator just afaik because they wanted to use commas for tuples and wanted to allow tuples to be written with or w/o enclosing parens, (* comments *), 2. +. 1., and other gnarly "symbol soup" bewilderment. Perhaps that's all necessary to make global type inference work seamlessly.</rant>