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

Implement a Way to Know Caller's Language #1289

Open
zoffixznet opened this Issue Dec 1, 2017 · 6 comments

Comments

Projects
4 participants
@zoffixznet
Copy link
Contributor

zoffixznet commented Dec 1, 2017

This was originally listed on 6.d-prep, but I'm filing it here, since this is the only known to me blocker for 6.d language release and I'd like to put more attention to it.

I can do all the work, but I'm unfamiliar with this area of the codebase and would need someone to give some hints on what needs to be implemented.

Per IRC comments the $*PERL variable is not suitable for this purpose and a proof of that is it doesn't appear to work right with precompiled modules.

<nine> 	.tell Zoffix Please do not use constructs like "$*PERL.version after v6.c". 
    That it does what you need it to do is a plain bug that really needs to be fixed.
    You are trying to get your caller's language version by accessing something
    that should be different only in lexical scope. $*PERL.version behaves
    completely bogus and unpredictable.
<nine> 	.tell Zoffix To make it clear: there is currently _no_ way at all to correctly
    do what you are trying. That's to me the single biggest blocker of 6.d.

I think lizmat++ proposed adding a variable similar to $/ that gets attached to blocks to indicate which language version should be used. Is this a suitable approach? And if it is, doesn't that mean our language version can be entirely lexical and you could have multiple language versions used in the same file?

@AlexDaniel AlexDaniel added the severe label Dec 8, 2017

@zoffixznet zoffixznet added the 6.d label Jan 19, 2018

@zoffixznet

This comment has been minimized.

Copy link
Contributor Author

zoffixznet commented Jan 24, 2018

@AlexDaniel

This comment has been minimized.

Copy link
Member

AlexDaniel commented Jun 17, 2018

This issue comes up very often. I understand that volunteers will do whatever they want to do, and that's fine, but it would be great if this issue got more attention. Maybe someone can write a step-by-step guide on how to get this done? Maybe a checklist of some sort? Or does anybody have any idea on how to get this thing moving?

@jnthn

This comment has been minimized.

Copy link
Member

jnthn commented Jun 18, 2018

I think before we can write an implementation guide, we need to decide what semantics we want, and make sure those support some concrete use cases.

The situation at present seems to be something like this:

  • Changes to the language grammar are entirely lexical in nature, and so easily handled by the use v6.x; mechanism. We do need to tighten up what we mean by "first non-whitespace thing in the file" rule, and then make sure the implementation enforces it. Clearly line comments should count (otherwise #!/usr/bin/perl6 cannot work out right), but what about Pod? Anyway, we need to tighten things up some, but this is for the most part a solved problem.
  • Loading a CORE.d.setting, which has the CORE.setting as its own setting, provides a mechanism to support new subs, multi candidates, hiding of candidates in the outer setting, and so forth. It can also support new types that need not be referenced from the main CORE.setting. We already use this mechanism to provide the new await semantics only for 6.d, for example. When this approach works, it works pretty well.
  • Anything that goes beyond these use cases is currently not possible to enforce any kind of language versioning on.

I figure the last point is the key one under consideration here. Here's some questions to try and get the ball rolling.

Do we want an imperative solution?

That is, are we expected code to be written like if the-effective-language-version-is(v6.d) { ... } else { ... }? Or are we looking at a more declarative solution, placed on certain language elements? I propose a couple of declarative ideas below, which you could imagine as being specified by traits on the applicable language element(s).

Do we want to declaratively specify the version availability of methods?

For example, we could provide ways to indicate:

  • This method can only be called by code of language version X or above (hidden to older versions)?
  • This method cannot be called by code of language version X or above (acts like it was removed in newer versions)?

But:

  • How will this work with method caching?
  • Is multiple dispatch to enforce this too?
    • How will this work with multi-dispatch caching?
    • Any considerations with regard to callwith?
  • What do meta-methods and introspection do?

Do we want to declaratively specify the version availability of types?

For example, we could provide a way to mark a type as "only available up to language version X" or "only available from language version X". But what would this mean?

  • The obvious semantic is that if we write the type literal a program in a version where it's not available, we get an error
  • What about late-bound lookups?
  • What about inheritance and role composition? Need to map out how things work here.

I think this is an orthogonal issue from versions of types themselves (e.g. Foo:ver<2>).

What is the effective language version?

It's not just as simple as "what is the language version of my caller".

One immediate case is where multiple dispatch where the proto is in one language and its caller is in another, and then the multi candidate cares about the effective language version. That could be resolved with the current "skip thunks" approach for an onlystr proto. But what about others? I suspect there will be other such cases.

Another issue is in code like:

use v6.c;
class Foo {
    method foo() { self.bar }
    method bar() {
        if the-effective-language-version-is(v6.d) { ... } else { ... }
    }
}

Which is then called by v6.d code. Which way should the branch go? (This is a genuine question. I really don't know. I fear we can write persuasive cases both ways. Do we need a way to mark code as language transparent? Do we want CLIENT::-like semantics? If yes, how to do that efficiently?)

This is an issue whether we have an imperative or a declarative approach. It feels to me like a declarative approach might be easier to optimize and have less edge-cases, but it may turn out to be just as bad.

tl;dr

At least on my part, it's not so much "volunteers will do whatever they want to do", but also that this isn't a trivial problem. I suspect anyone digging into it more deeply will realize the same (or they'll see a simple solution that I've not realized yet, which would be wonderful :-)). At the moment, I can't just write an implementation guide for willing volunteers, because I don't know what we should implement.

It's a difficult language design issue. It needs some proposals exploring, along with examples of concrete problems they solve. A solution potentially deals in performance-sensitive matters like dispatch, and so optimization has to be a consideration. An imperative solution probably would also have performance considerations ("how can we optimize out the condition"). Either way, "we'll figure out how to make that perform well later" isn't a good enough answer.

@zoffixznet

This comment has been minimized.

Copy link
Contributor Author

zoffixznet commented Jun 18, 2018

Anything that goes beyond these use cases is currently not possible to enforce any kind of language versioning on.

Maybe we should trim the list of 6.d changes and push anything that falls into that category to the to 6.e language.

@niner

This comment has been minimized.

Copy link
Contributor

niner commented Jun 18, 2018

Just an idle thought: don't spesh plugins give us a way to optimize an imperative if the-callers-language-version-is(v6.d)? Or would we even need spesh plugins for that? The caller's language version is a static property of the callsite. Spesh candidates are generated for callsites, so checks like that could be entirely eliminated safely.

Any way, my feeling is that it's gonna be a mixture of some declarative ways and a couple of imperative ifs scattered around. They all have their place.

zoffixznet added a commit to perl6/doc that referenced this issue Jun 28, 2018

Document .subst-mutate will be deprecated in future
Originally planned[^1] to be deprecated in 6.d for reasons[^1], but due to R#1289 [^2]
we're postponing it for later language versions.
[^1] https://github.com/perl6/6.d-prep/blob/master/TODO/FEATURES.md#deprecate-strsubst-mutate
[^2] rakudo/rakudo#1289

@zoffixznet zoffixznet added 6.e and removed 6.d severe labels Jun 28, 2018

@zoffixznet zoffixznet changed the title [6.d BLOCKER] Implement a Way to Know Caller's Language Implement a Way to Know Caller's Language Jun 28, 2018

zoffixznet added a commit to perl6/6.d-prep that referenced this issue Jul 30, 2018

Defer IEEE-fication of / to later versions
Tried implementing it, but hitting a problem on the same scope
as R#1289 rakudo/rakudo#1289

Basically the 6.d verions of the ops are currently loaded as if
they were just comming from a module and aren't visible by the
rest of the 6.c setting. There's a ton of trig and other math
ops that aren't affected by the change, so I'm deferring it, until
we figure out R#1289 and get a clearer picture on caller's lang ver.
@zoffixznet

This comment has been minimized.

Copy link
Contributor Author

zoffixznet commented Jul 30, 2018

Just hit another problem, similar in scope to the OP problem in the issue: perl6/6.d-prep@12b28ed

Basically, we want infix:</> with Nums to follow IEEE standard more closely. If I simply stick new versions of the ops in 6.d setting, then I get an ambiguous dispatch. I could solve it with is default trait (probably some minor perf hit with dispatch too?), however, the rest of the 6.c setting doesn't automagically switch to using the new versions of this op. So even if we IEEE-fy the / op, the trig/math routines that use it won't get that benefit and would need to be duplicated to 6.d version as well, which sounds like a Bad Idea™

So I differed that 6.d-prep item to later language versions, in case we figure out some better system for this stuff when this issue is resolved.


Another problem is EVALed code. For example a throws-like 「...」 currently will use compiler's default language rather than what the file with that test uses, because it EVALs that code string.

zoffixznet added a commit to perl6/roast that referenced this issue Oct 27, 2018

Compatibilize spec with language-switching compilers
6.c spec does not define how language switching is to behave, and
that is still largely undefined and lacks a PoV in 6.d spec due to
blockage by R#1289[^1]. The rudimentary PoV for language switching
currently does not propage the active language version to EVALed
code, and so `throws-like` tests with stringy code continue using
default compiler's language version.

Were that to be defined as the behaviour for language switching,
then the tests being modified by this commit would be deemed wrong,
as they do not set correct lang version. The same would actually
apply to all `throws-like` tests with Str argument. It's more likely
that this behaviour will be deemed unwanted and language switching
will be defined in a way that lets EVAL use caller's lang ver.

Since R#1289 isn't a trivial issue, I'm going to correct just these
couple of tests until language switching behaviour is more fully
defined. The change in a test module to move the version as first
line is also part of undefinedness of lang switching, which is
now more well-defined and makes it a requirement the lang is the
first statement in code.

[1] rakudo/rakudo#1289
[2] https://colabti.org/irclogger/irclogger_log/perl6-dev?date=2018-10-27#l140

@ugexe ugexe added this to To Do in 6.e Feb 25, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.