Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unable to use Sigilless variables with WHERE clause in CLASS?

Module A has a member variable name c, with a WHERE clause:

unit class A;

my \MAXVALUE = 1000_000;

has $.c where 0 < * < MAXVALUE;

method gist() {
    "$!c";
}

set RAKULIB environment variable:

set RAKULIB="d:\scripts\Raku\A\lib"      # Windows
export RAKULIB="/opt/scripts/Raku/A/lib" # Linux

use Module A like this:

use A;

my $a = A.new(c => 1);
say $a;

but got type check error:

Type check failed in binding to parameter '<anon>'; expected Any but got Mu (Mu)
  in whatevercode  at D:\scripts\Raku\Raku\A\lib\.precomp\C6EB86CB837D3BCAAA3D85B66CE337C820700C08\6D\6DCD4CE23D88E2EE9568BA546C007C63D9131C1B line 1
  in block <unit> at basic.rakutest line 3

Is this a bug?

raku version:

raku -v
This is Rakudo version 2020.05.1 built on MoarVM version 2020.05
implementing Raku 6.d.
like image 390
chenyf Avatar asked Mar 02 '21 10:03

chenyf


People also ask

How to make a where clause in a string variable?

Just build your query in a string variable, and execute it ! there may be 1 to 20 parament passed by user. and on the base of parameters query will work. I thought by adding strings in where clause it can be done. If user have not passed any parameter, you should not put a WHERE clause ! Or if you want, you can put a "WHERE 1=1" clause..

How do I use class descriptors in a where clause?

For most uses of class descriptors in a WHERE clause, WMI flags the query as invalid and returns an error. However, use the dot (.) operator for properties of type object in WMI. For example, the following query is valid if Prop is a valid property of MyClass and is type object:

What are the rules for where clause in WQL?

Moreover, the operator must be among the list of valid WQL operators. Either a property name or a constant must appear on either side of the operator in the WHERE clause. You may use string literals, such as "NTFS", in a WHERE clause.

What operators can be used in where clause in SQL?

SQL requires single quotes around text values (most database systems will also allow double quotes). The following operators can be used in the WHERE clause: Not equal. Note: In some versions of SQL this operator may be written as !=


1 Answers

Golfed to: BEGIN say 1 < Mu displays essentially the same error message.

In your code, MAXVALUE is initialized with the value Mu at compile time. You must alter your code so evaluation of ... < MAXVALUE comes after MAXVALUE has been initialized to have a value other than Mu.

In the rest of this answer:

  • What are the simplest compile time solutions?

  • What if you want to use a run-time value?

  • What's going on behind the scenes?

  • Is the error message LTA?

What are the simplest compile time solutions?

You yourself provide a good compile time solution in your comment below this answer in response to my first version of it.

That said, if you wish to keep the symbol purely lexically scoped, you should start with a my:

my constant MAXVALUE = 1000_000;

Problem solved.

What if you want to use a run-time value?

The variables/symbols/expressions in a where clause will be evaluated at compile-time if they're in a WhateverCode expression.

But that might not be the case if you use a lambda (with { ... } syntax) instead. If the line in your code:

has $.c where 0 < * < MAXVALUE;

was changed to:

has $.c where { 0 < $_ < MAXVALUE }

then your code would work.

BUT...

If you add an explicit initial value to the has line...

has $.c where { 0 < $_ < MAXVALUE } = 10;
                                    ^^^^ Explicit initialization

...then the error would return because now the where clause is invoked during compile time due to a chain reaction:

  • The compiler decides to check that the initialization value passes the where check.

  • To do that the compiler evaluates the where clause at compile-time;

  • That in turn causes MAXVALUE to be evaluated -- and it contains Mu at compile-time, causing the error to return.

What's going on behind the scenes?

There are both compile-time and run-time phases in initializing has variables:

  • During compile-time, when a class is being composed, the default value that instances will have for each has variable is determined. Three common scenarios are:

    has statement default value
    has $foo; Any
    has $foo where some-condition; <anon>
    has $foo = 42; 42
  • During run-time, when an instance of a class is being built, the values of the has variables of that particular instance are set, possibly initializing them to values other than the class's default values.

The following code is intended to demonstrate the process:

BEGIN say 'code compile-time, start, outside class';
say 'code run-time, start, outside class';

sub init (*%_) { say "initializing {|%_}" }

class foo {
  has $.bar;
  has $.baz where init(baz => $_);
  has $.buz where init(buz => $_) = 42;
  say 'run-time, at end of class';
  BEGIN say 'compile-time, at end of class';
}
BEGIN say 'compile-time, outside class again';

say 'run-time, outside class again';
say foo.new(buz => 99);

displays:

code compile-time, start, outside class
compile-time, at end of class
initializing buz    42
compile-time, outside class again
code run-time, start, outside class
run-time, at end of class
run-time, outside class again
initializing buz    99
foo.new(bar => Any, baz => <anon>, buz => 99)

Note the completed initializations of the three has variables in the fully built instance:

  • bar => Any.

    This is the usual default initialization of a variable.

  • baz => <anon>.

    cf say my Int $var; which displays (Int), because the default value of a variable with a type constraint but no explicit initializing value is the type object corresponding to the type constraint, and say my $var where 1; which displays (<anon>), reflecting the anonymous nature of a where constraint (as contrasted with a subset). So has $.baz where init(baz => $_); results in a default value of (<anon>).

  • buz => 99.

    This is the only has variable for which an initializing ... line was displayed -- and, importantly, there are two lines, not one:

    1. The first line is displayed immediately after compile-time, at end of class, i.e. when the compiler reaches the closing curly of the class declaration. This is when Raku does class composition, and buz gets the default value 42.

    2. Then, during evaluation of foo.new(buz => 99);, which builds an instance of the class at run-time, comes initializing 99.

Is the error message LTA?

In my first version of this answer I wrote:

I'm not myself able to provide a coherent explanation ... whether it's considered a bug. I do currently consider the error message LTA.

Now it's time for me to carefully discuss the error message:

Type check failed in binding to parameter '<anon>'; expected Any but got Mu (Mu)
  in whatevercode  at ... A\lib ... line 1
  in block <unit> at ... line 3
  • Type check failed ...

    The where check failed. It is referred to as a "type check". Given normal Raku use of the word "type", I'm going to count this as fine.

  • ... in binding to parameter '<anon>';

    I'm not sure what "parameter" refers to, nor '<anon>'. Imhh (in my humble hypothesizing) "parameter" refers to a parameter of the infix:«<» function and '<anon>' to the value stored in $.c at compile-time before the anonymous where constraint is attempted at run-time.

    LTA? Perhaps something like <where clause> instead of <anon> would be viable and appropriate?

  • expected Any but got Mu (Mu)

    By default, has variables expect Mu, not Any. So this bit of the message seems not to refer to the $.c. So, as with my hypothesis about "parameter", I think this is about a parameter of the infix:«<» function.

    This is really useful info. Any time you see but got Mu (Mu) you can be pretty sure a failure to initialize some value is part of the problem, as was indeed the case here.

  • in whatevercode

    The blow up is happening in a WhateverCode, so this part is useful for someone who knows what a WhateverCode is.

    LTA? If someone does not know what a WhateverCode is, this part is cryptic. I think in WhateverCode instead of in whatevercode would be a worthwhile improvement. Perhaps in WhateverCode (eg '* < 42'), where the '* < 42' is fixed as literally that rather than being the actual source whatevercode, because I don't think that's doable, would be better?

  • at ... A\lib ...

    The paths parts I've elided (...) are both helpful (full) and awful (long non-human friendly strings).

    LTA? Perhaps moving the paths to the end would help:

    Type check failed ... got Mu (Mu)
      in whatevercode at A\lib line 1
    
      (Full path to A\lib: D:\scripts\Raku\Raku\A\lib\.precomp\
          C6EB86CB837D3BCAAA3D85B66CE337C820700C08\
          6D\6DCD4CE23D88E2EE9568BA546C007C63D9131C1B)
    
  • ... line 1

    "line 1" presumably refers to either line 1 in the whatevercode or line 1 in the A\lib. Either way, it's not especially helpful.

    LTA? Perhaps it's viable and appropriate to make it clearer what the line 1 refers to, and, if it refers to A\lib, then make it accurately point to the whatevercode.

  • in block <unit> at line 3

    That's useful.

like image 169
raiph Avatar answered Sep 19 '22 17:09

raiph