Skip to content

Multi Helper#821

Merged
Perryvw merged 75 commits intoTypeScriptToLua:masterfrom
hazzard993:helpers
Dec 23, 2020
Merged

Multi Helper#821
Perryvw merged 75 commits intoTypeScriptToLua:masterfrom
hazzard993:helpers

Conversation

@hazzard993
Copy link
Contributor

@hazzard993 hazzard993 commented Feb 6, 2020

For #580

Giving a helper language-extension implementation a try.

This PR makes TypeScriptToLua declare the $multi function and MultiReturn type. These can be used as a type safe alternatives to @tupleReturn.

You'll be able to use something like the tsconfig.json below to get access to $multi.

{
  "compilerOptions": {
    "types": [
      "typescript-to-lua/language-extensions"
    ]
  }
}

This function can only be used in a ReturnStatement or as a return expression in an ArrowFunction.

const x = () => $multi(1, 2, 3);

function f() {
  return $multi(1, 2, 3);
}

@hazzard993 hazzard993 requested a review from ark120202 February 6, 2020 05:33
@ark120202
Copy link
Contributor

I think helpers name might need some bikeshedding. Thoughts on macro/macros?

@Perryvw Perryvw mentioned this pull request Dec 19, 2020
@lolleko
Copy link
Member

lolleko commented Dec 21, 2020

I think helpers name might need some bikeshedding. Thoughts on macro/macros?

I agree "helper" is too generic. but I don't think "macros" is the correct term.

Personally I would prefer "extension". It is still a very generic term, but that's the term used for c++ compiler/language extensions: (https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/C_002b_002b-Extensions.html , https://docs.microsoft.com/en-us/cpp/build/reference/microsoft-extensions-to-c-and-cpp?view=msvc-160)
For me these helpers seem to be exactly that, an extension to TS/Lua syntax...

@Perryvw
Copy link
Member

Perryvw commented Dec 21, 2020

I think helpers name might need some bikeshedding. Thoughts on macro/macros?

I agree "helper" is too generic. but I don't think "macros" is the correct term.

Personally I would prefer "extension". It is still a very generic term, but that's the term used for c++ compiler/language extensions: (https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/C_002b_002b-Extensions.html , https://docs.microsoft.com/en-us/cpp/build/reference/microsoft-extensions-to-c-and-cpp?view=msvc-160)
For me these helpers seem to be exactly that, an extension to TS/Lua syntax...

As discussed on discord, let's go with language-extensions if @hazzard993 agrees:
import { multi } from "typescript-to-lua/language-extensions";

@hazzard993
Copy link
Contributor Author

In regards to #947, pcall can best be defined like this using MultiReturn

type ToArray<T> = T extends any[] ? T : [T];

declare function pcall<F extends (...args: any[]) => any>(
  this: void,
  cb: F,
  ...args: Parameters<F>
): MultiReturn<
  | [false, string, ...undefined[]]
  | [true, ...ToArray<ReturnType<F>>]
>;

It looks like TypeScript needs a bit more work to assign the typings correctly

const [result, a, b, c] = pcall((a: number) => {
  return $multi(1, 2, 3);
}, 0);

result; // boolean
a; // string | number | true (expected string | number)
b; // string | number | boolean | undefined (expected number | undefined)
c; // string | number | boolean | undefined (expected number | undefined)

Copy link
Member

@Perryvw Perryvw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to

Copy link
Member

@Perryvw Perryvw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good, would like you to add one or a couple extra tests (see comments)

@Perryvw Perryvw merged commit 0cb8f5f into TypeScriptToLua:master Dec 23, 2020
@hazzard993 hazzard993 deleted the helpers branch December 23, 2020 19:10
@LoganDark
Copy link

Is MultiReturn<[true]> | MultiReturn<[false, string]> or MultiReturn<[true] | [false, string]> preferred? I've been using the former, but I don't know if that confuses anything or not.

@Perryvw
Copy link
Member

Perryvw commented Jan 3, 2021

@LoganDark From the few experiments I did it does not really matter, I was hoping one would provide proper type narrowing, but seems like for now neither do that. Maybe we can come up with a way to update the type later. For now I would probably go with the second option personally, but you can do whatever you prefer.

@LoganDark
Copy link

For now I would probably go with the second option personally, but you can do whatever you prefer.

The second one does provide the benefit of being definitely wrapped in exactly one outer MultiReturn. I'm using the first one right now, maybe I'll switch if there turn out being benefits to the other.

@LoganDark
Copy link

LoganDark commented Jan 3, 2021

There are issues:

  • const bytes = string.byte(...) errors ("expected a destructuring pattern") because string.byte returns a MultiReturn. I now have to do const bytes = [...string.byte(...)] which is annoying
  • string.byte('0')[1] generates string.byte("0")[1] in Lua, which is incorrect. It should either do (string.byte("0")), or ({string.byte("0")})[1] like it did before
  • let args = coroutine.resume(coro, ...params) generated local args = coroutine.resume(coro, __TS__Spread(params)) which is wrong. coroutine.resume's return type was MultiReturn<...> | MultiReturn<...>, MultiReturn<... | ...> fixed it, by forcing me to wrap it in [...<call>].

@Perryvw
Copy link
Member

Perryvw commented Jan 3, 2021

Instead of wrapping the right side you can also do it on the left instead: const [...bytes] = string.byte(...); to capture all, or const [byte] = string.byte(...) to capture the first one, or even a combination of the two: const [byte1, ...otherBytes] = string.byte(...).

@LoganDark
Copy link

LoganDark commented Jan 3, 2021

Instead of wrapping the right side you can also do it on the left instead: const [...bytes] = string.byte(...); to capture all, or const [byte] = string.byte(...) to capture the first one, or even a combination of the two: const [byte1, ...otherBytes] = string.byte(...).

Yeah, I suppose that's reasonable. It's still annoying that I have to spread it, though. I expected it to act just like the tuples did before. And that invalid code generation is still probably a bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants