Abstract Enums output code looks messy

149 views
Skip to first unread message

Adrian Martinez

unread,
Jun 28, 2015, 6:34:39 AM6/28/15
to haxe...@googlegroups.com
Hi all,

I’m currently working with abstract  enums.
But I can’t help noticing some unnecessary extra code genereated in my js output code.
I tried to recreate my case on http://try.haxe.org/#ADB6d

The output looks fine, but when looking in the js source on line 11 you see that Test 2 generated some extra code. Using the @:from keyword I was actually expecting Test 2 to look like Test 3.

In my local project the Test 2 case looks even weirder, it generates a function out of it that looks something like this:
(function($this) {
       
var $r;
       
var v = new MyType("Test 2");
        $r
= EnumTypes.TMyType(v);
       
return $r;
   
}(this))

I would suspect that the abstract @:from function causes this behaviour.
I wrote this code with the intention that the ouput code would look like Test 3:

EnumTypes.TMyType(new MyType("Test 3")

So my question is how can I let Test 2 generate in the same way as Test 3?

Adrian

Juraj Kirchheim

unread,
Jun 28, 2015, 9:24:38 AM6/28/15
to haxe...@googlegroups.com
Your local output probably looks that way, because you don't have `-D analyzer` turned on.

As for the rest, I don't know. You can always try a nightly and see if the problem goes away. Simn has been rather busy with the optimizer/analyzer, so it might be better already ... or worse :D.

I wouldn't worry too much. Just check if this is still the case and if so, report and issue. In the meantime, try take comfort from the fact that allocating the enum will be more expensive than creating a useless variable to hold it ;)

Best,
Juraj

--
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 Martinez

unread,
Jun 30, 2015, 3:42:01 AM6/30/15
to haxe...@googlegroups.com
Hi Juraj,

That’s right -D analyzer ouptuts the code just as on try.axe.org.
I tried a nightly but it didn’t resolve the issue.

Well I can not help working because this is something I use very extensively throughout my projects. And I don’t want my code to be slowed down by unnecessary assignments every time I call a method that uses an abstract enum as argument.

Using Dynamic instead of Enum fixes the output for now: http://try.haxe.org/#1EF58
See the js source on line 5 for the output I wished to have using my previous technic.
But of course using Dynamic is not according to the Haxe philosophy :-(

Yesterday I did another test, and in this test I wanted to use chaining: doThis().doThat().doAnotherThing() on an abstract: http://try.haxe.org/#3aD79
But using this technic on an abstract resulted the same messy code output where I expected a single line of linear method calls. (See the js source on line 4)

Chaining is something I tend to use as much as possible since it allows for very flexible coding and looks very neat. But apparently I can’t use this technic on abstracts :-/

Adrian

Op zondag 28 juni 2015 15:24:38 UTC+2 schreef back2dos:

Simon Krajewski

unread,
Jun 30, 2015, 4:22:51 AM6/30/15
to haxe...@googlegroups.com
Am 30.06.2015 um 09:42 schrieb Adrian Martinez:
> Hi Juraj,
>
> That’s right -D analyzer ouptuts the code just as on try.axe.org.
> I tried a nightly but it didn’t resolve the issue.
>
> Well I can not help working because this is something I use very
> extensively throughout my projects. And I don’t want my code to be
> slowed down by unnecessary assignments every time I call a method that
> uses an abstract enum as argument.
>
> Using Dynamic instead of Enum fixes the output for now:
> http://try.haxe.org/#1EF58
> See the js source on line 5 for the output I wished to have using my
> previous technic.
> But of course using Dynamic is not according to the Haxe philosophy :-(
>
> Yesterday I did another test, and in this test I wanted to use
> chaining: doThis().doThat().doAnotherThing() on an abstract:
> http://try.haxe.org/#3aD79
> But using this technic on an abstract resulted the same messy code
> output where I expected a single line of linear method calls. (See the
> js source on line 4)
>
> Chaining is something I tend to use as much as possible since it
> allows for very flexible coding and looks very neat. But apparently I
> can’t use this technic on abstracts :-/

This is not (really) related to abstracts. The problem is that inlining
has to deal with potential side-effects. Look at this example, then try
to imagine what the output would be if the temp var wasn't forced:
http://try.haxe.org/#45B73

I agree the output could be improved, but this is not as easy as you
might think and requires some strategy.

Simon

Juraj Kirchheim

unread,
Jun 30, 2015, 5:34:31 AM6/30/15
to haxe...@googlegroups.com
On Tue, Jun 30, 2015 at 9:42 AM, Adrian Martinez <adria...@gmail.com> wrote:
Hi Juraj,

That’s right -D analyzer ouptuts the code just as on try.axe.org.
I tried a nightly but it didn’t resolve the issue.

Well I can not help working because this is something I use very extensively throughout my projects. And I don’t want my code to be slowed down by unnecessary assignments every time I call a method that uses an abstract enum as argument.

As I said before, Adrian, it doesn't matter. Your code creates an enum, that has an instance as argument. That's two allocations. Consider this example: http://try.haxe.org/#9D5e6

Chrome:

Test.hx:6: 0.0010001659393310547s
Test.hx:18: 0.03699994087219238s

IE:

Test.hx:5: 0.002000093460083008s
Test.hx:16: 0.13000011444091797s

FF:

Test.hx:5: 0.0010001659393310547s
Test.hx:16: 1.0439999103546143s

The first number measures a couple of extra assignments, the second one measures the allocations. The first one is 1 to 3 *orders of magnitude* faster. 

Using Dynamic instead of Enum fixes the output for now: http://try.haxe.org/#1EF58
See the js source on line 5 for the output I wished to have using my previous technic.
But of course using Dynamic is not according to the Haxe philosophy :-(

What you can do would be to remove the `inline` on the function, which is what creates the noise as Simn already said. But if your measure the two, you might very well find out that the inlined version is ultimately faster (although this is not always the case either).
 
Yesterday I did another test, and in this test I wanted to use chaining: doThis().doThat().doAnotherThing() on an abstract: http://try.haxe.org/#3aD79
But using this technic on an abstract resulted the same messy code output where I expected a single line of linear method calls. (See the js source on line 4)

It is *output*. It is not meant to be pretty. It is meant to be readable enough for debugging purposes and nothing more. Beyond that, it is meant to be reasonably small and reasonably fast. And if you measure it, you will actually find that it is.
 
Chaining is something I tend to use as much as possible since it allows for very flexible coding and looks very neat. But apparently I can’t use this technic on abstracts :-/

I'm sorry Adrian, but I think you have it backwards.

To quote SICP: "programs must be written for people to read, and only incidentally for machines to execute."
And Knuth: "Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered."

If you consider that chaining to be more readable, then by all means, go for it! Don't even bother adding `inline` to the methods unless you *know* it's going to have a desirable result. When you see the performance of your program deteriorate, profile to identify the bottlenecks and then optimize those.

Why would you write less readable code, if for one it does not actually impact performance significantly, and secondly, if getting better output is just a matter of waiting for the compiler to improve? Do you really want to work around this now, only to have to revisit all of your code once the compiler deals with it to your satisfaction?

Ultimately, it is for you to choose. But I think you're going to make your life unnecessarily hard, if you let the (ever improving) state of the js generator dictate your API design.

Best,
Juraj

Adrian Martinez

unread,
Jun 30, 2015, 8:44:21 AM6/30/15
to haxe...@googlegroups.com
Hi Simon,

Aaah I think I understand now :)
The arguments have first to be initialised before they’re set in place.

A fix could be to check on every argument whether it has to be initialised or not.
If it's a primitive value, string, object etc. it can be put in place.
If not, there’s no other option but to use a tmp variable to initialise it beforehand.

Another thing to think about is if one uses inline maybe he also should be aware that arguments are set directly in place and not initialised beforehand. Not sure about this but for me this is more logical since they’re not real functions.

For me the main reason of using inline is for optimising my output code, not compromising it ;o)

Would be awesome if this could be improved since I use inline very much throughout my projects.

Adrian

Op dinsdag 30 juni 2015 10:22:51 UTC+2 schreef Simon Krajewski:

Adrian Martinez

unread,
Jun 30, 2015, 9:05:36 AM6/30/15
to haxe...@googlegroups.com
Hi Juraj, thanks for your example.

I applied your test on my own case, check it out: http://try.haxe.org/#2389D
The first one tests the Abstract Enum which I intended to use in the first place.
The second one tests the Enum without the inlined abstract aspect.
And the third one tests the argument as being Dynamic

Here are my result in FF:
13:29:26:396   Test.hx:6: 1.561999797821045s
13:29:27:849   Test.hx:14: 1.4519999027252197s
13:29:27:868   Test.hx:22: 0.018000125885009766s

The first test with the inlined abstract element is slightly slower then the second one without the inlined abstract element. So your right about the fact that the difference is very small as a result of using extra assignments. The difference is very small but yet unnecessary. It’s also a matter of principal, why loosing speed on assignments that are not necessary? Also it increases the file in size and other non-haxe programmers are not gonna dig the extra load.

As in for pretty output code, I’m not asking for a work of art :P Just code that is optimised as much as possible. Where you guys already did a great job doing so due to macros, absrtacts, and the inline element :D :D :D

The third test is yet a whole other story, the Dynamic test is immensely faster than the tests with the Enums. I didn’t espect the difference between the Enum and Dynamic would be so big. The downside of course is that it is not typed according to the Haxe philosophy. Concerning this I was wondering if it's possible to use an Enum in Haxe for having it typed but then outputing Dynamic for a better performance?

Maybe a little miscommunication but I don’t use chaining for a better performance. I hope it does... but my main reason is for readability, and more pleasant coding. Consider this code:

Without chaining:
var a = new A();
a
.doThis();
a
.doThat();

var b = new B();
b
.doWhatever();
b
.useThis( a );

trace
( b.toString() );

With chaining:
trace(
   
new B()
   
.doWhatever()
   
.useThis(
       
new A()
       
.doThis()
       
.doThat()
   
)
   
.toString()
);

You see, it’s leaner, easier to read and coding wise more pleasant if you ask me. In this small example the difference is not really big but when the case scenario gets bigger, chaining really improves in readability, overview and so on.

Adrian

Op dinsdag 30 juni 2015 11:34:31 UTC+2 schreef back2dos:

Benjamin Dubois

unread,
Jul 1, 2015, 1:28:18 AM7/1/15
to haxe...@googlegroups.com
God! your using chaining inside function call argument and find it more readable?
You are actually trying to start a troll?

--

Juraj Kirchheim

unread,
Jul 1, 2015, 1:34:38 AM7/1/15
to haxe...@googlegroups.com
No reason to be judgemental, Ben ;) 

We all have very different views of what makes code readable and what doesn't, because ultimately it's a matter of personal habit.

Best,
Juraj

Adrian Martinez

unread,
Jul 1, 2015, 4:25:20 AM7/1/15
to haxe...@googlegroups.com
Benjamin Dubois, don’t forget JQuery is also based for a great part on chaining.
So this is not something new, neither am I trolling around ;-)
It also depends on which case scenario’s you use it. Furthermore the code does not demand you to use it, it’s just an option for the ones who prefer it. When initiating lots of methods, building certain structures and keeping the overview of the hierarchy is where chaining comes in handy. It also requires less code and has code completion all the way.

Op woensdag 1 juli 2015 07:28:18 UTC+2 schreef Benjamin Dubois:

Benjamin Dubois

unread,
Jul 1, 2015, 7:35:41 AM7/1/15
to haxe...@googlegroups.com
alright I was the one trolling :).
Juraj is right, it's everyone coding preference. I generally find that functions called (even not chained) as another function argument make debugging harder.

Just as side note, at my company, we have set jquery usage in the stak of js bad practices and recommend the usage of querySelector/All instead with some exceptions (.css() and few others I don't have in mind).
But it may be irrelevant since I failed to convince people to use Haxe so far.
Reply all
Reply to author
Forward
0 new messages