abstract sucks, it should go away (click bait)

294 views
Skip to first unread message

Jeff Ward

unread,
Jun 11, 2015, 11:00:34 AM6/11/15
to haxe...@googlegroups.com
Language design question - why does abstract exist?

Hear me out.  It unlocks some really cool features -- implicit casts, array access, ...  So the question then becomes:

Why can't you just add these features to class?

Plus "abstract class" has a different connotation in programming at large (from Java to C++ to php to C#) - pretty much everyone agrees it means a base class that can't be directly implemented.

Haxe says that abstract classes "defines types "over" concrete types in order to modify or augment their behavior" -- so wait, why wouldn't I just extend the class?

So the devil's advocate (me) says: Haxe used the wrong word, and the awesome functionality (mainly @:from, @:to, @:arrayAccess) should just be available to all classes. Adding another class-like type with a specific and incompatible feature-set just confuses things.

luca mezzalira

unread,
Jun 11, 2015, 11:05:05 AM6/11/15
to haxe...@googlegroups.com
Jeff I'm 110% with you.

I was discussing with a bunch of friends about that, an abstract is another thing in several programming languages, why can we call it in another way?
I agree also on embedding that inside concrete classes, it makes more sense for me too.

my 2 cents

Daniel Glazman

unread,
Jun 11, 2015, 11:25:50 AM6/11/15
to haxe...@googlegroups.com
On 11/06/2015 17:00, Jeff Ward wrote:

> So the devil's advocate (me) says: Haxe used the wrong word, and the
> awesome functionality (mainly @:from, @:to, @:arrayAccess) should just
> be available to all classes. Adding another class-like type with a
> specific and incompatible feature-set just confuses
> things.

100% agreed.

</Daniel>

Fernando Serboncini

unread,
Jun 11, 2015, 11:29:36 AM6/11/15
to haxe...@googlegroups.com
This always struck me as one the really ugly Haxe corners. :/
So +1 to everything you said.

--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.

Adrian Veith

unread,
Jun 11, 2015, 11:55:05 AM6/11/15
to haxe...@googlegroups.com
abstract is maybe not the best name - BUT abstract are not limited to class types ! So having an extra construct is much more powerful than just extending classes.

cheers Adrian.

Juraj Kirchheim

unread,
Jun 11, 2015, 12:17:59 PM6/11/15
to haxe...@googlegroups.com
On Thu, Jun 11, 2015 at 5:00 PM, Jeff Ward <jeff...@gmail.com> wrote:
Language design question - why does abstract exist?

Hear me out.  It unlocks some really cool features -- implicit casts, array access, ...  So the question then becomes:

Why can't you just add these features to class?

In many cases it's not a matter of "just" adding it, because abstracts do not have inheritance, which makes it easier to figure out what function to actually use. Also, why?
 
Plus "abstract class" has a different connotation in programming at large (from Java to C++ to php to C#) - pretty much everyone agrees it means a base class that can't be directly implemented.

That's right. On is called an "abstract class", the other an "abstract". That's it. You do know there is a difference between "milk chocolate" and "milk"?

Haxe says that abstract classes "defines types "over" concrete types in order to modify or augment their behavior" -- so wait, why wouldn't I just extend the class?

An abstract completely hides the underlying type and is incompatible with it. This is a very powerful concept, called abstraction. If you are not with it, then please get SICP.

So the devil's advocate (me) says: Haxe used the wrong word, and the awesome functionality (mainly @:from, @:to, @:arrayAccess) should just be available to all classes. Adding another class-like type with a specific and incompatible feature-set just confuses things.

So long as you seem confused about what abstracts are for, I have strong reservations about trusting your judgement on what Haxe did wrong again in this instance. If you want something clarified, then please ask. In a civil manner.

Best,
Juraj

Jeff Ward

unread,
Jun 11, 2015, 1:29:41 PM6/11/15
to haxe...@googlegroups.com
Hi Adrian - good point, I'll review abstract enums, are there other uses?

Hi Juraj, thanks for chiming in. The post was intended to be civil (if a bit playful, with an admitted click bait title.)

Do I have a right to question Haxe language design? Perhaps not. Am I proficient with haxe? Absolutely not. Am I making an effort to learn? Definitely, and I've been using it off and on for ~9 months. So I'd think my perceptions represent valuable feedback from a beginner.

Do I understand abstract? Well, I try to build on examples presented here and in the Haxe manual, and my efforts are continually thwarted. Abstract doesn't retain the concrete class's resolve capability. And resolve can't have array access. Sigh.

So what I find confusing is - Haxe has all these powerful constructs, but every time I try to apply them, I hit a disallowed corner case. It feels symptomatic of an overly complicated system, hence my thought on simplification - let's talk pros/cons of removing abstract.

But I persist, because the lure of Haxe is too great to ignore, and I hope my feedback is met with consideration and as you say, civil discourse.

So on to the actual issues:

> An abstract completely hides the underlying type and is incompatible with it. This is a very powerful concept, called abstraction

That can be achieved with composition (If you're not with it, get this wikipedia article.) You could argue that abstraction happens at compile-time, but if you inline the composition accessors, then I presume there's little difference remaining.

> Also, why (add abstract features to class)?

To simplify. To make one construct that's consistent instead of two that are similar but different. To occupy less space in my (the language user's) brain.

Best,
Jeff


Mark Knol

unread,
Jun 11, 2015, 2:35:55 PM6/11/15
to haxe...@googlegroups.com
I think you should give it a try. I slowly adopt abstract types in my system, and it very nice. I think you are kinda right about composition, but I think this is a form of composition, only on type level. The link you mentioned is on object level, but the principles remains, beside the fact it not only add functionality, you can also restrict how it is used and how casting should work. I think it's been solved quite elegant in the language design.

Johann

unread,
Jun 11, 2015, 5:51:13 PM6/11/15
to haxe...@googlegroups.com


On Thursday, June 11, 2015 at 7:29:41 PM UTC+2, Jeff Ward wrote: [...]

Hi Jeff.

A few words about abstract types. Haxe uses the correct term. An abstract [type] is more general than an "abstract class", which is one specific kind of many possible abstract types that happens to be more or less common in OOP languages, another specific example for an abstract type is the plain old interface. Abstract types are a well-defined term in type theory, where they are also referred to as existential types. Abstracts, by now, are a core concept of the Haxe language, they are a major step in its evolution, even. They allow to capture an abstraction in a type that can then be implemented in many different ways, if required. 

How is that useful?
The most prominent example are integers. They are represented by abstract types in Haxe. The various Haxe targets don't all have compatible Integer representations, if they have one at all. So what do we need for that? ***We need the abstraction of an integer, give it a type, and then do our best to implement it for a given platform.*** That's what abstracts are being used and what they are useful for.

And because that concept is so extremely powerful, it has been exposed to the user of the language. There are enums (better known as algebraic data types), anonymous structures, function types, interfaces, other basic types, and possibly target-platform-native types that have to be handled in some way to be usable from Haxe. All of these can be wrapped in abstracts. You can use an existing type and give it your own semantics, and be sure it won't be conflated with that other (the underlying) type.

Let's take an integer example again. Assume you need a very efficient way to encode a 2D point - with x and y components, with maximum values of, say, 38400 for each component. Since that fits into 16 bits, and our Int is at least 32 bits wide, you can use Int as underlying type.  Voila. Now, do you really want to argue that this abstract Point should better be a class, let alone an abstract one? 
 
Do I have a right to question Haxe language design? Perhaps not.

Do you feel qualified to question it? 

  
[..] So I'd think my perceptions represent valuable feedback from a beginner.

Frankly, if a beginner in automotive engineering starts questioning the necessity of wheels without knowing what they do and without presenting a hell of a practical alternative, then no, it's not really valuable. 


Do I understand abstract?

No, not at all.

So what I find confusing is - Haxe has all these powerful constructs, but every time I try to apply them, I hit a disallowed corner case. It feels symptomatic of an overly complicated system, hence my thought on simplification - let's talk pros/cons of removing abstract.


Perhaps we should start with talking about knowing what we're talking about.

regards, 
Johann

Mark Knol

unread,
Jun 11, 2015, 6:30:29 PM6/11/15
to haxe...@googlegroups.com
Very nice explanation.
Offtopic: If you inline that constructor too, the output is really small. \o/ http://try.haxe.org/#1D361

Philippe Elsass

unread,
Jun 11, 2015, 6:30:48 PM6/11/15
to haxe...@googlegroups.com
An interesting side question is: why doesn't 'resolve' allow array access? Is there anything preventing it? Could it be added?

--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.



--
Philippe

Jeff Ward

unread,
Jun 11, 2015, 8:06:31 PM6/11/15
to haxe...@googlegroups.com
Johann - I'll ignore the personal attacks, since I suppose my sarcastic / aggressive tone invited them. Thank you for the explanation. Though I will point out that some other compiler magic (static analysis?) causes your Point/Int example to output the same .js code whether using a class or an abstract (sadly, in c++, using class does cause an allocation.)

Philippe - Yes, that is one of my main questions.

Justin Donaldson

unread,
Jun 12, 2015, 1:24:37 AM6/12/15
to Haxe
Just chiming in to repeat that abstract types are completely different than abstract classes.  I strongly urge folks to read up on abstract *types* and to put the notion of abstract *classes* completely out of mind, they're not at all related.  Abstract types are extremely powerful, perhaps second only to macros.  Quite simply, If you're not getting it you're missing out.  

For instance, with an abstract type you could prepare a typedef for a server response.  If any of the response field strings are not sanitized, you can mark them as an "Unsafe" type that wraps a string.  In the abstract logic, you can translate the Unsafe type to a String type via the typical html escape mechanism.  Since the sanitization step happens implicitly, it is implemented completely lazily... only when needed when an Unsafe is passed to a method that accepts strings.  
This is great! Normally to a compiler a string is a string... but in the real world this is not the case... some strings should not be passed to certain methods in certain situations.  Abstracts give you a way to describe a server response with more resolution, and prevent a large number of security and output related problems with very minor overhead.

Here's a more advanced abstract example that implements compressed arrays:
This lets me save ~40% of the space required for arrays in certain cases.  Keep in mind that a packed array type is *not* an object that wraps an array (as it is in many other languages).  At runtime, it is just a plain array, making it very efficient.

So, I suppose an abstract could suck, but only if you intentionally add the appropriate implicit cast.  I don't think they should go away!


 

On Thu, Jun 11, 2015 at 7:06 PM, Jeff Ward <jeff...@gmail.com> wrote:
Johann - I'll ignore the personal attacks, since I suppose my sarcastic / aggressive tone invited them. Thank you for the explanation. Though I will point out that some other compiler magic (static analysis?) causes your Point/Int example to output the same .js code whether using a class or an abstract (sadly, in c++, using class does cause an allocation.)

Philippe - Yes, that is one of my main questions.

--

David Elahee

unread,
Jun 12, 2015, 1:29:14 AM6/12/15
to haxe...@googlegroups.com

Their nature is very different from classes since they have no runtime existence they are much more similar to typedefs with stamina.

Adding these feature to regular classes would just make the class system fatty and hard to maintain,  not to say confusing for users which will not understand why some classes do not have runtime existence.

The runtime existence is a crucial point for optimisation, ergonomy and type tuning, it avoid many memory indirection which allows to have a very fast primitives like efficient bytes impl etc....

Maybe the name abstract is a cognitive pain though...but the feature is needed so imvho it can't go.

Jeff Ward

unread,
Jun 12, 2015, 1:52:23 AM6/12/15
to haxe...@googlegroups.com
Justin - thanks for more interesting use cases. The use of abstract types is becoming quite clear, thank you all.

David,

> Adding these feature to regular classes would just make the class system fatty and hard to maintain

I dunno, I'd think Array Access on normal classes would be highly useful (which as Philippe points out, if resolve could handle arrayAccess, that'd suffice.)

Interestingly, Brendon pointed out that in the git version of Haxe, abstracts may be getting @:resolve, which means I'll be able to use abstract to create a type that defines both dot access and array access - my whole use case in the first place.

Currently class can customize dot access, and abstract can define array access -- a seemingly bizarre state of affairs.

Johann

unread,
Jun 12, 2015, 2:15:33 AM6/12/15
to haxe...@googlegroups.com


On Friday, June 12, 2015 at 2:06:31 AM UTC+2, Jeff Ward wrote:
Johann - I'll ignore the personal attacks, since I suppose my sarcastic / aggressive tone invited them.

I have no idea what you assume to be a personal attack, but I'd be interested in clarifying.
 
Thank you for the explanation. Though I will point out that some other compiler magic (static analysis?) causes your Point/Int example to output the same .js code whether using a class or an abstract

No, it might be reduced to individual local vars if the reference isn't passed to other functions, or stored in some instance or static field, but I'd be very surprised if the compiler decides to narrow integers on its own. 
Where's the code that does that?

(sadly, in c++, using class does cause an allocation.)

Philippe - Yes, that is one of my main questions.

Operator overloading, which largely is orthogonal to what abstracts are and do, could be added to classes as well. It is simply a design decision. 

regards,
Johann

Gama11

unread,
Jun 12, 2015, 3:33:42 AM6/12/15
to haxe...@googlegroups.com
Abstracts are definitely very powerful. Flixel uses an integer abstract to represent a color, providing a ton of useful utility methods and properties without any runtime overhead / need to create objects, since after compilation, any FlxColor is just a plain old Int.

By the way, there's an open issue about operator overloading via static extensions on the Haxe repository (and even an experimental implementation on a branch of Simn's fork).

Johann

unread,
Jun 12, 2015, 3:49:29 AM6/12/15
to haxe...@googlegroups.com

 
On Friday, June 12, 2015 at 2:06:31 AM UTC+2, Jeff Ward wrote:
Johann - I'll ignore the personal attacks, since I suppose my sarcastic / aggressive tone invited them.

Actually I'll clarify right away. 

If someone starts talking about language design and suggests to remove a feature from a language that is extensively used throughout the core language and in many libraries (and that's something anyone who knows how to search in text files can find out easily), it should be obvious that removing it will break a lot of existing code, introducing a major backwards-incompatible change. And while you annotated the topic with "click bait" you repeated the suggestion to remove abstracts without the slightest indication of not being serious about it later. In such a case there are two possible interpretations:

1. You don't understand what you're talking about and hence can't properly assess the implications of your proposal. 
2. You understand what you're talking about - in that case it's an act of open hostility and you want to introduce backwards incompatibility, want to break everyone's code, including the compiler and standard library, inevitably leading to horrible friction, tons of unnecessary work and all sorts of headaches and pain. 

I chose 1. - the benevolent interpretation - and I also told you about it, but that's not a personal attack by any means.

regards, 
Johann

David Elahee

unread,
Jun 12, 2015, 3:50:20 AM6/12/15
to haxe...@googlegroups.com
@jeff

A pretty awesome use of abstract: https://github.com/mandel59/unifill/

abstract here will save so much memory indirections :)

Array access for classes...frankly this would induce _very_ bad practices as using the dynamicity will crush down your performances gyuu.... if it is abstract it is ok as it generates typed codes...

Abstract really kinda revolves around performances and hidden cost removal you know and ergonomics. 

Frankly, people asking for suppression do not seem (imvho) too grasp the full extent of this feature because of the bad wording...So i would prefer you require a clearer documentation or rename rather than pure deletion :)




--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.



--
David Elahee


Philippe Elsass

unread,
Jun 12, 2015, 4:12:00 AM6/12/15
to haxe...@googlegroups.com

I don't think anyone is really suggesting to remove abstracts. It's a call for explanations.

Like macros, the more concrete examples can be provided (like the recent macro examples repo which should be linked in the doc if it isn't), the better.

Jeff Ward

unread,
Jun 12, 2015, 10:54:00 AM6/12/15
to haxe...@googlegroups.com
@Gamma11 - that's really slick. Color as integers is something that most devs are familiar with, and unlike using an enum or a set of static helper function, this allows you to keep all the functionality related to manipulating colors in a convenient type that happens to boil down to an Int at runtime.

Perhaps the abstract type example in the manual would better be color -- then I'd change the enum example to something other than color, though I realize that was. Since Haxe provides so many possibilities, the most interesting examples, imo, are why you'd use feature X (e.g. abstract Color(Int)) over feature Y (e.g. enum Color).

Johann - the second indication of sarcasm was "devil's advocate". It means I'm going to argue for a likely unpopular position (the removal of abstract) because I think the ensuing discussion will be insightful, not that I believe it will actually happen. My reservations about abstracts were real, and I've certainly learned a lot. Sorry that I seemed aggressive - peace, friend. =)

So the bit that's valuable is the takeaways from the discussion - there is a cost to abstract types, they do cause user confusion, both in their name and that they seem similar to classes while providing a different set of features, and confusion poses a barrier to adoption. But they have an imperative use in the cross-platform nature of Haxe (building a set of consistent, cross-platform types upon platforms with different concrete types) and they provide benefits in expressiveness and performance beyond normal class inheritance and composition.

Also, some really cool current work over at the Haxe repo was pointed out -- sweet!

I may submit some suggestions for the Haxe manual to try and capture some of the insightful points made in this thread.

Cheers and thanks everyone.

Joshua Granick

unread,
Jun 12, 2015, 11:12:15 AM6/12/15
to haxe...@googlegroups.com
You could also do:

@:enum abstract Color(Int) from Int to Int {

    public var RED = 0xFFFF0000;
    public var GREEN = 0xFF00FF00;
    public var BLUE = 0xFF0000FF;

}

etc.

You could do Color.RED, or switch (color) but also feed any value you want instead, too. Abstract enums, especially, have been valuable for C++ and Haxe interaction, since you can have enum behavior in Haxe, while still being able to work transparently over CFFI with native libraries :)

Just 2 cents, if the static extension method is sound, array access for classes would be AWESOME, and really come in handy for classes like openfl.utils.ByteArray

Franco Ponticelli

unread,
Jun 12, 2015, 11:23:56 AM6/12/15
to haxe...@googlegroups.com
thx.color does the same for RGB (https://github.com/fponticelli/thx.color/blob/master/src/thx/color/Rgb.hx) and many other color spaces.

--

Jeff Ward

unread,
Jun 12, 2015, 11:30:42 AM6/12/15
to haxe...@googlegroups.com
Blast, Joshua, there I was happy and you upset the balance by introducing something new. =)

Too many choices is actually bad, because I (the beginner) burn too many cycles trying to understand which is best and never actually start writing code. Partial joke, partial truth. =D

Alright, I'm off to synthesize abstract enums... the C++ / Haxe / CFFI example is beyond my head-space right now.

Maybe that's the overall problem with learning Haxe. Inquisitive learners want to know why, and the why is ever beyond their reach.

Justin Donaldson

unread,
Jun 12, 2015, 3:24:40 PM6/12/15
to Haxe
On Fri, Jun 12, 2015 at 10:30 AM, Jeff Ward <jeff...@gmail.com> wrote:
Blast, Joshua, there I was happy and you upset the balance by introducing something new. =)

Too many choices is actually bad, because I (the beginner) burn too many cycles trying to understand which is best and never actually start writing code. Partial joke, partial truth. =D

Alright, I'm off to synthesize abstract enums... the C++ / Haxe / CFFI example is beyond my head-space right now.

Maybe that's the overall problem with learning Haxe. Inquisitive learners want to know why, and the why is ever beyond their reach.

One of the things I like best about Haxe is that there's always more "why".  The surface area of the language is just huge... it needs to cover all these platform inconsistencies on a very low level.  Abstract types are one critical tool towards that end.  

I do agree that docs could be better, but the surface area for docs and training is huge as well.  Folks coming from a js background would probably need very different information than folks coming from a java background.  Also, folks developing pure mobile apps are probably interested in different parts of the language as compared to folks developing pure server apps.

Finally, most of the veterans on this list have criticized the language at some point or another.  We won't hold it against you.




Jeff Ward

unread,
Jun 12, 2015, 4:42:14 PM6/12/15
to haxe...@googlegroups.com
Lol, thanks Justin. =)

Andreas Söderlund

unread,
Jun 12, 2015, 7:35:05 PM6/12/15
to haxe...@googlegroups.com
Abstract classes are very similar to what the DCI architecture call Roles, or more precise Roles and Role methods. A Role is basically an identifier (the reference to the abstract class) and the Role methods are a collection of methods connected to the Role (the methods available on the abstract class).

The purpose of a Role is to augment an object to create the actual functionality of the system. The difference between DCI Roles and abstract classes is that the latter can be global, but Roles and their Role methods are always private within a Context in DCI. This is because the Role responsibilities only makes sense within a specific Use case. For example, a Shape object can move and draw in a graphical context, a Cowboy can move, draw and shoot in a Western movie context. Having a Role that can draw and shoot does not make it a candidate for reuse in another Context.

I implemented the first DCI library for Haxe with abstract classes, but switched to a Context-aware and cleaner syntax later. If you want to know more, check out the haxedci-example repo for a DCI introduction.


/Andreas

Reply all
Reply to author
Forward
0 new messages