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

Closed
zoffixznet opened this issue Dec 1, 2017 · 12 comments
Closed

Implement a Way to Know Caller's Language #1289

zoffixznet opened this issue Dec 1, 2017 · 12 comments
Labels
Projects

Comments

@zoffixznet
Copy link
Contributor

@zoffixznet 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?

@zoffixznet
Copy link
Contributor Author

@zoffixznet zoffixznet commented Jan 24, 2018

@AlexDaniel
Copy link
Contributor

@AlexDaniel 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
Copy link
Member

@jnthn 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
Copy link
Contributor Author

@zoffixznet 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
Copy link
Collaborator

@niner 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 Raku/doc that referenced this issue Jun 28, 2018
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 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 Raku/6.d-prep that referenced this issue Jul 30, 2018
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
Copy link
Contributor Author

@zoffixznet zoffixznet commented Jul 30, 2018

Just hit another problem, similar in scope to the OP problem in the issue: Raku/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 Raku/roast that referenced this issue Oct 27, 2018
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
@vrurg
Copy link
Member

@vrurg vrurg commented Jul 14, 2019

Suggestion: a unit can carry a symbol containing language revision the unit was compiled with. Then knowing your caller's language would be as simple as CALLER::UNIT::<LANGUAGE-REVISION>.

Another possible solution could be use of CORE-SETTING-REV sub declared in all CORE.setting. I yet need to check it out, but CALLER::LEXICAL::<&CORE-SETTING-REV> would return the correct language revision.

@lizmat
Copy link
Contributor

@lizmat lizmat commented Jul 14, 2019

Yes, I think that idea's been floated already. I'm not sure what happened to that, or why it would be a bad idea.

@vrurg
Copy link
Member

@vrurg vrurg commented Jul 15, 2019

I have tested and can confirm that &CALLER::LEXICAL::CORE-SETTING-REV does provide correct information about caller's language. Or, for that matter, caller's innermost CORE.setting version. BTW, from this point of view &CALLER::SETTING::CORE-SETTING-REV would be more correct name space.

The only thing which stops me from closing this ticket is the fact that CORE-SETTING-REV is a sub. Using it all over the place is highly ineffective thing performance-wise. It could as well be a constant, but there is a bug which results in only constants from the base CORE.setting are being used for compile-time lexical resolution. I.e.:

use v6.e.PREVIEW;
say CORE-SETTING-REV-CONSTANT; # c
say LEXICAL::CORE-SETTING-REV-CONSTANT; # e

@vrurg
Copy link
Member

@vrurg vrurg commented Jul 17, 2019

Closing via #3055. Caller language version is now available via CALLER::SETTING::CORE-SETTING-REV constant. For example:

rev-6d.pm:

use v6.d;
unit module rev-d;

sub rev-foo is export {
    say "MOD REV: ", CORE-SETTING-REV; 
    say "CALLER:  ", CALLER::SETTING::CORE-SETTING-REV;
}

caller-ver.p6:

use v6.e.PREVIEW;
use rev-d;

say "SCRIPT REV: ", CORE-SETTING-REV;
rev-foo;

The script outputs:

SCRIPT REV: e
MOD REV: d
CALLER:  e

In nqp nqp::getlexcaller("CORE-SETTING-REV") should do too.

@vrurg vrurg closed this Jul 17, 2019
@vrurg vrurg moved this from To Do to Done in 6.e Aug 27, 2019
@raiph
Copy link
Contributor

@raiph raiph commented Mar 9, 2020

Hi @vrurg,

Thanks for the work you do! :)

Has someone distributed to other GH issues the aspects jnthn wrote about?

If so, do these all share some tag or similar which can be searched for to find them?

If not, would you be able to provide a pointer to substantive discussion among core devs about how they plan to tackle the thorny issues jnthn raised, or to core devs actively agreeing not to do so (presumably punting them to 6.f or beyond)?

I'm hoping for something better than "try searching the IRC logs and/or GH issues for keywords X, Y or Z" but even that would be OK if you're saying you know the things I find if I do so will clarify what core devs plan for the future of raku language versioning.

TIA for any comment.

@vrurg
Copy link
Member

@vrurg vrurg commented Mar 9, 2020

@raiph There were not much done to formally cover all aspects of the problem. But the most critical issues were discussed. First of all, rakudo docs now have a Jonathan's article on class versioning:

https://github.com/rakudo/rakudo/blob/master/docs/articles/2016-02%20Proposed%20Perl%206%20Versioning%20And%20Compatibility%20Guidelines.md

Also I can point you this problem-solving:

Raku/problem-solving#71

That's all I can come up with right now.

No specific attention was given to problem tracking issues related to this subject either. As always, it's a matter of time, you know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
6.e
  
Done
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
7 participants