Re: [scala-language] The cake’s problem, dotty des ign and the approach to modularity.

Shelby <[email protected]>
Newsgroups gmane.comp.lang.scala
Message-ID <[email protected]>
I believe this post is illuminating. I hope to get some feedback.

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.

For the goal of completely solving the Expression Problem, I believe the 
requirement for a "global vtable" which I pondered upthread, is implicitly 
fulfilled by the injection of inversion-of-control I had proposed.

Objects are passed around as the vtable, which I believe is a form of the 
extensible modularity advantage Martin was referring to in the thread 
"Usefulness of OOP":

https://groups.google.com/d/msg/scala-language/PIhmEeMg-Ms/3AE0udamW5EJ
http://www.scala-lang.org/old/node/1637

Here is my example which afaics (?) could not be achieved with subclassing 
(i.e. virtual inheritance with a vtable bound to each instance) without the 
overhead of reconstructing a copy of the List with "pimp my library" 
instances:

trait Drawable[T] {
  def draw(o: T): Unit
}

class Point(x: Int, y: Int)
class Line(a: Point, b: Point)

implicit object LineDrawable extends Drawable[Line] {
  def draw(line: Line)...
}

// OT: below I'm pseudo-coding a hypothetical `List[T]` design that can't 
throw an exception when accessing head— which last time I checked some 
years ago Scala's standard library design unfortunately does.

def draw[T](list: List[T])(implicit drawable: Drawable[T]) { list match { 
case Head(head) => drawable.draw(head) case Nil => } }

draw(List(Line(Point(0,0), Point(1,1))))

trait DrawableMorphed[T] {
  def drawMorphed(o: T): Unit
}

implicit class MorphedDrawable[T](drawable: Drawable[T]) extends 
DrawableMorphed[T] {
  def drawMorphed(o: T) { drawable.draw(o) } // OT: code for morphing of 
input `o` is not shown, given it is irrelevant noise to what is being 
elucidated
}

def draw2[T](list: List[T])(implicit drawable: DrawableMorphed[T]) { list 
match { case Head(head) => drawable.drawMorphed(head) case Nil => } }

def draw3[T](list: List[T])(implicit drawable: Drawable[T]) { draw2(list) }


The subclassing anti-pattern rears its ugly head again though as implicit 
subsumption as in the following example:

class Box(a: Point, b: Point, slope: Point) // OT: to insure the 
construction can't throw an exception, use only the diagonal corners and 
slope of one of the edges

implicit object BoxDrawable extends Drawable[Box] {
  def draw(box: Box)...
}

draw(List(Line(Point(0,0), Point(1,1)), Box(Point(0,0), Point(1,1), 
Point(0,1)))) // Error: no implicit found for Drawable[Any]

I assume the new DOT calculus will instead implicitly subsume `T` to `Line ∨ 
Box` instead of `Any`?

Perhaps the Dotty compiler could automatically generate the implicit object 
`Drawable[Line ∨ Box]`. Thus we retain subtyping (i.e. `Line` and `Box` are 
subtypes of `Line ∨ Box`) while eliminating subclassing (i.e. there is no 
nominal type which is the supertype of `Line ∨ Box` or at least `Any` 
should only occur with a cast since I've shown it discards extensible 
static typing). I am not clear if this is modeled by the fine grained 
methods structural typing in DOT that Adiaan Moors alluded to in the 
context of a prior discussion about a union type in one of the Scala 
discussion group threads (can't seem to locate it quickly at the moment); 
or if could be modeled in the compiler employing a monad, e.g. see the 
`sequence` conversion of `List[Thing[T]]` to `Thing[List[T]]` where the 
disjunction would be a list of types in the disjunction such as `DisjunctionList[Drawable[T]]` 
converted to the necessary implicit `Drawable[DisjunctionList[T]]`:

http://www.codecommit.com/blog/ruby/monads-are-not-metaphors


Another benefit of deprecating subsumption via subclassing in favor of 
subtyped disjunction, is distinct invariantly parametrized types can be 
added to the same List:

class TaggedLine[Tag](a: Point, b: Point, tag: TAG)...

draw(List(TaggedLine(Point(0,0), Point(1,1), 
1), List(TaggedLine(Point(0,0), Point(1,1), "1"))) // Error: can not 
subsume to List[TaggedLine[Any]] because TAG is invariant

I assume the new DOT calculus will instead implicitly subsume `TAG` to `Int ∨ 
String` instead of `Any`?

Somewhat OT, I am pondering how will DOT deal with the following?

trait Invertible[T <: Invertible[T, A, B], A, B] {
  def to(a: A): B
  def from(b: B): A
}

object AB extends Invertible[AB, A, B] {
  def to(a: A): B...
  def from(b: B): A...
}

object CD extends Invertible[CD, C, D] {
  def to(c: C): D...
  def from(d: D): C...
}

def to[T, A, B](invertible: Invertible[T, A, B], a: A): B = invertible.to(a)

f(AB ∧ CD, new A)
f(AB ∧ CD, new C)

So the Dotty compiler has to automatically supply:

object `AB ∧ CD` extends Invertible[`AB ∧ CD`, A ∨ C, B ∨ D] {
  def to(a: A): B...
  def to(a: C): D...
  def from(b: B): A...
  def from(d: D): C...
}

On Sunday, July 5, 2015 at 11:50:07 PM UTC+8, Shelby wrote:
>
> 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?
>
>
> [1] 
> https://existentialtype.wordpress.com/2011/03/16/what-is-a-functional-language/
>
> "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."
>
>
> http://tonymorris.github.io/blog/posts/what-kind-of-things-are-easy-in-haskell-and-hard-in-scala-and-vice-versa/index.html
>
> "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."
>
> [2] https://existentialtype.wordpress.com/2011/03/15/boolean-blindness/
>
> "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)."
>
> [3] 
> https://existentialtype.wordpress.com/2011/03/16/what-is-a-functional-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."
>
> [4] http://hammerprinciple.com/therighttool
> http://joshbassett.info/2013/hello-haskell-goodbye-scala/
> http://blog.samibadawi.com/2013/02/scala-vs-haskell-vs-python.html
> http://jnordenberg.blogspot.com/2012/05/my-take-on-haskell-vs-scala.html
>
> http://blog.srinivasan.biz/software/if-you-have-to-learn-just-one-programming-language
>
> http://tonymorris.github.io/blog/posts/what-kind-of-things-are-easy-in-haskell-and-hard-in-scala-and-vice-versa/index.html
>
> "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"
>
> [5] 
> https://www.reddit.com/r/haskell/comments/3aqj67/in_what_ways_does_haskell_support_intersection/
>

... 

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.