Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: Allow basic inlining. #2721

Closed
zpdDG4gta8XKpMCd opened this issue Apr 11, 2015 · 12 comments
Closed

Suggestion: Allow basic inlining. #2721

zpdDG4gta8XKpMCd opened this issue Apr 11, 2015 · 12 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@zpdDG4gta8XKpMCd
Copy link

Please make it possible to inline the identity function because it enables a lot of useful things in TS.

So if a function is expression-based (has only a return statement) it should be trivial to inline, so please consider allowing such inlining.

Consider the example: Type hijacking

/** A measured number. */
interface N<a> {
   'a measured number': N<a>;
   'it uses a': a;
}
interface MHz { 'a megaherz': MHz }
interface Tick { 'a tick': Tick; }

/** the solely purpose of this function is to trick the TS type system, it should be inlined */
function toN<a>(value: number) : N<a> {
   return <any> value;
}
function add<a>(left: N<a>, right: N<a>) : N<a> {
   return <any> left + <any> right;
}
var freq = toN<MHz>(10000);   // <-- toN is only to trick the TS type system, unnecessary runtime overhead, needs to be inlined
var time = toN<Tick>(new Date().getTime()); // <-- toN is only to trick the TS type system, unnecessary runtime overhead, needs to be inlined
var hm = add(freq, time); //  <-- poor man's units of measure in action
@mhegazy
Copy link
Contributor

mhegazy commented Apr 11, 2015

Why not just do:

var freq: MHz = <any>(10000);
var time:Tick = <any>(new Date().getTime()); 
var hm = add(freq, time);

@zpdDG4gta8XKpMCd
Copy link
Author

type safety

var freq: N<MHz> = <any> { 
    type: Type.HeavyBulldozer,
    manufacturer: 'Caterpillar',
    length: 26.5,
    width: 14.7,
    height: 13,
    weight: 108000,
    propulsion:  Propulsion.Tracks,
    engine: 'CAT C18 ACERT',
    grossPower: 464,
    flywheelPower: 410,
    drawbarPull: 71.6,
    speed: {
        forward: 7.3,
        reverse: 9.1
    },
    bladeCapacity: 17.7
};

@DanielRosenwasser
Copy link
Member

I get what you're trying to do, but I this tends to be beyond the scope of TypeScript. As mentioned in #661, there is a complexity associated with doing something like this, and it's difficult to get right. If all you want is for us to inline the identity function, that seems like an extremely awkward compromise for a specific use case.

@yahiko00
Copy link

Inlining numerical functions and some "macro-like" functions could be useful imho.

@zpdDG4gta8XKpMCd
Copy link
Author

Inlining can be trivial if the next 2 assumptions are met:

  • no statements other than a single return statement
  • function only depends on its parameters.

It would be incredibly helpful to have such basic inlining, and it doesnt
take much to implement. Again, we are not asking for a general case
inlining which is really hard, expression-like functions that meet the
assumptions above are trivial to inline.
On Apr 11, 2015 3:35 PM, "Daniel Rosenwasser" notifications@github.com
wrote:

I get what you're trying to do, but I this tends to be beyond the scope of
TypeScript. As mentioned in #661
#661, there is a
complexity associated with doing something like this, and it's difficult to
get right. If all you want is for us to inline the identity function, that
seems like an extremely awkward compromise for a specific use case.

Reply to this email directly or view it on GitHub
#2721 (comment)
.

@CyrusNajmabadi
Copy link
Contributor

I'm not sure why we'd want TypeScript to do this. Won't your JS engine already do this for you?

@zpdDG4gta8XKpMCd
Copy link
Author

Does it? If you know please share, there must be a spec or a white paper or
release notes of some sort about it that say "our JavaScript engine will
optimize your identity function 100%". I haven't seen any.

On Sat, Apr 11, 2015 at 10:05 PM, CyrusNajmabadi notifications@github.com
wrote:

I'm not sure why we'd want TypeScript to do this. Won't your JS engine
already do this for you?

Reply to this email directly or view it on GitHub
#2721 (comment)
.

Aleksey Bykov

@zpdDG4gta8XKpMCd
Copy link
Author

Not sure about your confusion. Isn't deterministic inlining a nice tool to have? Just like that spread operator or those computable properties or all other syntax sugar we got from the latest TS release. However unlike focusing on the developer's comfort and convenience it addresses the performance issues by giving you the most you can get out of a piece of a code (without sacrificing its modularity and maintainability). That is a common sense reason why anyone might want it.

When you say that JavaScript engines will do it for you, you might or might not be right. At least the performance tests that I ran recently suggest that IE11 still does NOT do it (sadly): https://jsperf.com/addition-operator-vs-add-function
And if they do it's up to their heuristics whether to do it or not. Why would anyone want to play a guess game if the problem can have be solved deterministically?

If you confusion comes from how complex inlining is in a general case, please read earlier comments that address it.

@CyrusNajmabadi
Copy link
Contributor

Isn't deterministic inlining a nice tool to have?

Not necessarily. It adds complexity to the language and may not justify its cost.

Why would anyone want to play a guess game if the problem can have be solved deterministically?

Because i haven't been convinced it's in the scope of the TypeScript project, or that it's the right solution for the supposed problem.

Note: when i try out the jsperf tests, i get numbers close enough that i don't feel this is warranted. Optimizations, inlining and whatnot seem well within the realm of the actual runtime engine. The engines seem to do a good enough job, so i don't think there is value in us investing here over the vast amount of other features we're considering.

Inlining can be trivial if the next 2 assumptions are met:

  • no statements other than a single return statement
  • function only depends on its parameters.

If this is true, then it's unclear to me why the engines would not be the right place for this sort of optimization. They can best make these determinations, and can best decide if inlining is worth it or not.

Note that inlining is not necessarily a perf win, and there is ample demonstrative history in compilers about how inlining can make things worse (for example, because of the code size increase you now have from inlining). Again, the runtimes seem the best places for these determinations to be made.

Finally, keep in mind that was want to keep your emitted code as close to your original code as we can. And, as mentioned in our design goals, it is a non-goal for us tp 'Aggressively optimize the runtime performance of programs.'

@DanielRosenwasser DanielRosenwasser added Suggestion An idea for TypeScript Out of Scope This idea sits outside of the TypeScript language design constraints labels Apr 12, 2015
@mhegazy
Copy link
Contributor

mhegazy commented Apr 12, 2015

In lining, along with other optimizations like constant propagation, dead code elimination, and tree shaking, would fit better under the minification bucket (tacked by #8).

I understand this request as an optimization feature; the part i do not understand is referencing this in the scenario above. I feel that the use of the function here is artificial, and does not result in type safety. I would assume what your really want is #364.

@zpdDG4gta8XKpMCd
Copy link
Author

@mhegazy Type hijacking is tricking TS into thinking that a value of one type is a value of another (usually more complex) type. It enables many interesting use cases by taking familiar types and extending or limiting them to a new set of operations (new algebra). As an example of this is one can simulate units of measure, that only allow arithmetics on numbers if their units are in agreement. How cool is that! As you have mentioned it is still in discussion whether it will be a first class feature of TypeScript. Hijacking can be done brutally just by casting a value to a necessary type, or more carefully and safely with special functions that take a value of the original type and return a value of a expected type. In fact with the types stripped off all such functions are just identity functions that just return back the given argument. While casting allows getting any type from any other one, the special functions only allow certain types to some other certain ones. The latter way is more desired since gives the control of what can be done and what cannot be because of making no sense. Now with special functions in place (which as we know are just identity functions) we get more control over what type can be transform to what, but it comes at the price of some runtime overhead since calling a function requires pushing values to the stack and getting back the result from there. And here is exactly where my question comes in, how about instead of calling a function that doesn't do anything, we just replace it by the value of its argument essentially doing inlining.

@yahiko00
Copy link

This suggestion should be reopened later when TypeScript fully complies with ES6 which is the top target as far as I understand.

@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants