emojicode / emojicode

πŸ˜€πŸ˜œπŸ”‚ World’s only programming language that’s bursting with emojis

Home Page:https://emojicode.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error using generic type inside a Callable

joeskeen opened this issue Β· comments

I'm trying to create a generic method that returns a callable using the generic type, but it throws an error. Here's the minimal code required to trigger the issue:

πŸ‡ πŸ’™ πŸ‡
  πŸ’­ generic instance method πŸš™β—
  πŸ’­ - of type A which can be anything (βšͺ)
  πŸ’­ - which returns a callable:
  πŸ’­   - which takes a value of type A
  πŸ’­   - and returns a value of type A
  β—πŸš™πŸšAβšͺπŸ† ➑️ πŸ‡A ➑️ AπŸ‰ πŸ‡
    πŸ’­ define the callable using the generic type parameter A
    πŸ‡πŸŽπŸ₯‘ val A ➑️ A
      ↩️ val
    πŸ‰ ➑️ callable
    ↩️ callable
  πŸ‰
πŸ‰

πŸπŸ‡πŸ‰

which results in the following compiler error:

generic-callables.πŸ‡:9:13: 🚨 error: No such generic type variable "A".
    πŸ‡ val A ➑️ A
          ⬆️

I've reviewed the Callables documentation as well as multiple others parts of the Language Reference and Package Index several times, but I'm not seeing anything I'm missing. How do I accomplish what I'm trying to do (use an outer generic type parameter inside a callable)?

P.S. It doesn't matter whether I use 🎍πŸ₯‘ or not, I get the same error.

I've tried to work around the problem, without any success:

$ emojicodec parser.πŸ‡
parser.πŸ‡:74:23: 🚨 error: No such generic type variable "A".
    πŸ‡πŸŽπŸ₯‘ stringπŸ”‘ ➑️ πŸ¬πŸ†ŽπŸšAπŸ†
                      ⬆️

$ emojicodec parser.πŸ‡
parser.πŸ‡:74:8: 🚨 error: Unexpected token Generic.
    πŸ‡πŸŽπŸ₯‘🐚AβšͺπŸ† stringπŸ”‘ ➑️ πŸ¬πŸ†ŽπŸšAπŸ†
       ⬆️

$ emojicodec parser.πŸ‡
parser.πŸ‡:74:6: 🚨 error: Unexpected token Generic.
    πŸ‡πŸšAβšͺπŸ†πŸŽπŸ₯‘ stringπŸ”‘ ➑️ πŸ¬πŸ†ŽπŸšAπŸ†
     ⬆️

It seems that Callables cannot be generic, or use any generic parameters inside them?

I'd be just as happy to just pass a reference to a generic method (as something like a Delegate) instead of using a Callable, but I have not discovered a way to do that either.

commented

Thanks for raising this interesting issue. I agree that it should work. The way the compiler is implemented, however, is that it does not use the method's type context when analysing closures. Instead a new type context similar to the one in🏁 is used, which is why you cannot access any generic type variables. I think this could be fixed by passing down the type context when analysing the closure but I'm not sure if that would have any side effects.

Closures themselves cannot have generic type parameters as callables cannot be generic themselves. If we wanted to allow that, fixing the above would be more complicated and involve keeping a list of parent functions in the type context.

I'd be just as happy to just pass a reference to a generic method (as something like a Delegate) instead of using a Callable, but I have not discovered a way to do that either.

I'm not exactly sure I understand what you want to do, but have you looked into solving this using an OO approach. Maybe you can define a protocol for your delegate or use a functor?

I'd be just as happy to just pass a reference to a generic method (as something like a Delegate) instead of using a Callable, but I have not discovered a way to do that either.

Sorry for the ambiguous comment. Words are hard. What I mean is something like what I could do in other languages such as JavaScript:

function doSomething(func) {
  func('hello');
}

doSomething(console.log);

In this example, console.log is a built-in function (you could think of it as a method of the Console class?), but I can pass it as if it were a value of type Function (Callable). Not sure how this would be possible in EmojiCode though. I think that your comment perhaps provides a way though:

Maybe you can define a protocol

This would work, but is limited to a single implementation for that protocol for that class. From the example above, we wouldn't be able to do an equivalent of:

doSomething(console.log);
doSomething(console.warn);
doSomething(console.info);
doSomething(console.error);

Instead it's the equivalent of

doSomething(console);

where console implements a log function. Of course, it's possible to expand into multiple classes to accomplish this, but it's much less succinct:

class Log  { 
  log(val) { console.log(val); }
}
const log = new Log();
doSomething(log);

class Warn { 
  log(val) { console.warn(val); }
}
const warn = new Warn();
doSomething(warn);

class Info { 
  log(val) { console.info(val); }
}
const info = new Info();
doSomething(info);

class Error { 
  log(val) { console.error(val); }
}
const error = new Error();
doSomething(error);

In conclusion, it seems that EmojiCode is designed for OOP and not Functional programming. Is that correct? Is there any path to making either work?

commented

You can always create a closure to bind a method to a specific object.

For example, to create a callable that invokes πŸ”‘ on integer with a specified base:

45 ➑️ integer
πŸ‡base πŸ”’ ➑️ πŸ”‘ ↩️ πŸ”‘ integer base ❗️ πŸ‰ ➑️ callable
πŸ˜€ ⁉️callable 16❗️ ❗️ πŸ’­ 2d

This would be equivalent to the following JavaScript:

const integer = new Number(45);
const fn = integer.toString.bind(integer);
console.log(fn(16)); // 2d

Note that const fn2 = integer.toString would not be enough and fn2(16) would raise an exception. The call to bind produces a function equivalent to (base) => integer.toString(base). Emojicode used to have a built-in operator that functioned like bind (it was called 🌢) but it was removed at some point because it made the language more complex.

Emojicode is certainly not Haskell, but you should be able to write functional programs as in other multi-paradigm languages just fine.