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

passing an instance of a domain model into Eval ? #79

Closed
aktxyz opened this issue Nov 19, 2022 · 12 comments
Closed

passing an instance of a domain model into Eval ? #79

aktxyz opened this issue Nov 19, 2022 · 12 comments

Comments

@aktxyz
Copy link

aktxyz commented Nov 19, 2022

I asked something similar in the flutter_eval project, but now that I think about it, this is probably more of a dart_eval thing.

I have a package with a bunch of class definitions that contain the main models for my project.

I would like to pass an instance of one of these models into the eval'd code and use some of the model properties in the eval'd code.

Is there a way to do something like that?

@aktxyz
Copy link
Author

aktxyz commented Nov 20, 2022

Looking at the example with the TimestampedTime class, it looks like there is a fair amount of boilerplate to create, and with a nested domain model, it can probably get a bit hairy (code gen would be awesome!)

If flinging random classes into eval is a pain, what about passing in a Map<String,String> ? I gave that a quick go and it had compile issues ... which I kind of expected as the whole Map thing is probably not allowed.

I took the flutter_eval example, and added this to the code to be compiled ...

    class MyWidget extends StatelessWidget {
      MyWidget(this.name,this.o);
      final String name;
      final Map<String, String> mymap;   // <<<<< added this 

And then added this to the EvalWidget properties ... where mymap is a Map<String,String> with a few entries.

args: [$String('SomeName'), $Object(mymap)],

@ethanblake4
Copy link
Owner

Hmm, can you try using an $Map instead of an $Object?

If there's still an error please paste the message.

@aktxyz
Copy link
Author

aktxyz commented Nov 20, 2022

Somehow I missed $Map, which sounds perfect.

I tried the following 2 way to pass in my map ...

EvalWidget(
  ...
  args: [$String('MyName'), $Map('mymap', map)],
)

EvalWidget(
  ...
  args: [$String('MyName'), $Map<String, String>('mymap', map)],
)

and get this error in my console ...

════════ Exception caught by widgets library ═══════════════════════════════════
dart_eval runtime exception: type 'BridgeSuperShim' is not a subtype of type '$InstanceImpl' in type cast

RUNTIME STATE
=============
Program offset: 34254
Stack sample: [L0: $"MyName", L1: Instance of '$Map<String, String>', L2: Instance of 'BridgeSuperShim', L3: Instance of '$InstanceImpl', L4: null, L5: null, L6: null, L7: null, L8: null, L9: null]
Call stack: [0, -1]
TRACE:
34248: PushReturnValue ()
34249: Return (L10)
34250: Pop (1)
34251: PushScope (F42:100, 'MyWidget.()')
34252: PushBridgeSuperShim ()
34253: CreateClass (F42:"MyWidget", super L1, vLen=1))
34254: SetObjectPropertyImpl (L2[0] = L0)  <<< EXCEPTION
34255: BridgeInstantiate (subclass L2, Ex#12))
34256: ParentBridgeSuperShim (shim L1, bridge L3)
34257: Return (L3)

The relevant error-causing widget was
EvalWidget
lib\…\SecureTestWidget.dart:72
══════════════════════════════════════════════════════════

@ethanblake4
Copy link
Owner

That looks like an argument count mismatch to me. Are you sure the constructor is still taking 2 arguments?

@aktxyz
Copy link
Author

aktxyz commented Nov 20, 2022

Well you nailed that one ... my fault after too much copy/paste trial/error stuff.

Thanks for all the help btw.

Now I am getting ...

════════ Exception caught by widgets library ═══════════════════════════════════
The following RuntimeException was thrown building $StatelessWidget$bridge(dirty):
dart_eval runtime exception: NoSuchMethodError: The getter '$value' was called on null.
Receiver: null
Tried calling: $value
...
RUNTIME STATE
=============
Program offset: 34236
Stack sample: [L0: $StatelessWidget$bridge, L1: Instance of '$BuildContext', L2: {test: value}, L3: $"test", L4: null, L5: null, L6: Instance of '$double', L7: Instance of '$EdgeInsets', L8: null, L9: Instance of '$MainAxisAlignment']
Call stack: [0, -1]

It's not liking my passed in Map<String,String>, it looks like in the eval'd code the Map may actually be null. Here is the eval'd widget code (mostly just the normal example code) and the code that creates the widget ...

    import 'package:flutter/material.dart';
    
    class MyWidget extends StatelessWidget {
      MyWidget(this.name, this.map);
      final String name;
      final Map<String,String> map;

      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: EdgeInsets.all(5.0),
          child: Column(children: [
              Container(
                color: Colors.red,
                child: Text('The name is !!! ' + name + ' !!! ' + map['test'] )
              )
            ],
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
          )
        );
      }
    }

I am using creating the widget like so ...

EvalWidget(
      packages: {
        'example': {
          'main.dart': myWidgetCode,
        }
      },
      assetPath: 'assets/program.evc',
      library: 'package:example/main.dart',
      function: 'MyWidget.',
      args: [
        $String('MyName'),
        $Map<String, String>('map', {"test": "value"})
      ],
    )

@aktxyz
Copy link
Author

aktxyz commented Nov 20, 2022

It looks like runtimeOverride is returning null, I was not really sure what the id parameter was for on $Map, so was just using a random string, and it looks like that is probably ok.

When I go to use the map in the eval'd widget like this map['test'] ... the $getProperty method is never getting called, and it seems like it should.

https://github.com/ethanblake4/dart_eval/blob/master/lib/src/eval/shared/stdlib/core/map.dart#L14

@ethanblake4
Copy link
Owner

ethanblake4 commented Nov 21, 2022

First of all, you should be using $Map.wrap which does not use runtimeOverride.

Anyway, after a little investigation it looks like you have to box the contents of the $Map too, not just the map itself.

So instead of:

$Map<String, String>('map', {"test": "value"})

you'd put:

$Map<$String, $String>.wrap({$String("test"): $String("value")})

Hope that helps!

@aktxyz
Copy link
Author

aktxyz commented Nov 21, 2022

With that example it is starting to make some sense.

But alas, with the above change to calling EvalWidget (and with the same widget code) ...


════════ Exception caught by widgets library ═══════════════════════════════════
dart_eval runtime exception: type 'String' is not a subtype of type '$Value?' in type cast
#0      _CastListBase.[] (dart:_internal/cast.dart:99:46)
#1      $String._concat
package:dart_eval/…/core/base.dart:235
#2      $Function.call
package:dart_eval/…/runtime/function.dart:93

RUNTIME STATE
=============
Program offset: 34236
Stack sample: [L0: $StatelessWidget$bridge, L1: Instance of '$BuildContext', L2: {$"test": $"value"}, L3: $"test", L4: "asdf", L5: null, L6: Instance of '$double', L7: Instance of '$EdgeInsets', L8: null, L9: Instance of '$MainAxisAlignment']
Call stack: [0, -1]
TRACE:
34230: PushConstant (C4)
34231: BoxString (L17)

@ethanblake4
Copy link
Owner

Hi @aktxyz sorry for the late reply, I have been busy with family.
I'm unable to reproduce this error, I tested your code exactly as you wrote and it works perfectly fine for me.

If you can link me to a repo containing the full code that causes the error I'll take another look.

@aktxyz
Copy link
Author

aktxyz commented Nov 27, 2022

hmm, that is great to know, I will get a repo together to share, thanks !

@aktxyz
Copy link
Author

aktxyz commented Nov 27, 2022

Ha, of course when I make a small sample repo, it works fine. It turns out my main issue was accessing the length property on the map ... which was causing this error _CastError (Null check operator used on a null value).

Other errors were caused by flailing around trying to see what caused the NullCheck error.

Thanks !

var widgetSource = '''
import 'package:flutter/material.dart';

class TestWidget2 extends StatelessWidget {
  TestWidget2(this.name, this.map);
  final String name;
  final Map<String, String> map;

  @override
  Widget build(BuildContext context) {
    var test = map['test'];
    //var n = map.length;     ***** this line causes the error *****
    return Text('The name parameter value ... ' + name + ' / ' + test);
  }
}
''';

@ethanblake4
Copy link
Owner

Ah yeah, that will be fixed when I get around to #9. Glad it's working otherwise!

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

No branches or pull requests

2 participants