Quantcast
Channel: ClearScript
Viewing all 2297 articles
Browse latest View live

New Post: for/in loop in JScript standards mode

$
0
0
Hi again,

We have a set of Javascripts that work with Google Chrome and Firefox and we would rather not modify them with non-standard code.

Just curious, why are you using JScript? V8 provides much better performance and Chrome compatibility, and it isn't affected by the issue you discovered.

What makes you think this is a problem with JScript? It is able to enumerate JScript objects, I would imagine it is using some kind of IDispatch/Ex capability.

We've investigated this internally and found some surprising things. When Standards Mode is enabled, JScript subtly breaks the IDispatchEx contract in order to pass some extra data to the host for certain calls. Hosts such as Internet Explorer and JScript itself can handle this, but the CLR cannot, and ClearScript relies on the CLR's built-in IDispatchEx implementation. The for..in loop isn't the only feature affected by this; host property deletion also fails in Standards Mode, and there may be others.

It may be possible to work around this problem. We're still investigating.

Thanks again!

Reopened Issue: for/in loop in JScript standards mode fails [94]

$
0
0
It appears that the for/in loop is not working when JScript engine is initialized with WindowsScriptEngineFlags.EnableStandardsMode flag.

I tried adding PropertyBag and ExpandoObject as host objects.

I noticed that there is a ScriptEngineException when executing for/in loop on either of the two objects which has HResult of 0x800a0005 (Invalid procedure call or argument).

Without WindowsScriptEngineFlags.EnableStandardsMode flag everything works without exceptions.

I am developing on Windows 10 with ClearScript 5.4.3

Here is the sample program:

```
static void Main(string[] args)
{
var engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
engine.AddHostType("Console", typeof(Console));

dynamic expandoObj = new ExpandoObject();
expandoObj.testProp = "expando testProp Text";
engine.AddHostObject("expandoObj", expandoObj);

var propertyBag = new PropertyBag();
propertyBag["testProp"] = "property bag testProp Text";
engine.AddHostObject("propertyBagObj", propertyBag);

engine.Execute(@"Console.WriteLine('expandoObj.testProp=' + expandoObj.testProp);");
engine.Execute(@"Console.WriteLine('propertyBagObj.testProp=' + propertyBagObj.testProp);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in propertyBagObj) Console.WriteLine('propertyBagObj[' + item + ']=' + propertyBagObj[item]);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in expandoObj) Console.WriteLine('expandoObj[' + item + ']=' + expandoObj[item]);");

}

```

Edited Issue: for/in loop in JScript standards mode fails [94]

$
0
0
It appears that the for/in loop is not working when JScript engine is initialized with WindowsScriptEngineFlags.EnableStandardsMode flag.

I tried adding PropertyBag and ExpandoObject as host objects.

I noticed that there is a ScriptEngineException when executing for/in loop on either of the two objects which has HResult of 0x800a0005 (Invalid procedure call or argument).

Without WindowsScriptEngineFlags.EnableStandardsMode flag everything works without exceptions.

I am developing on Windows 10 with ClearScript 5.4.3

Here is the sample program:

```
static void Main(string[] args)
{
var engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
engine.AddHostType("Console", typeof(Console));

dynamic expandoObj = new ExpandoObject();
expandoObj.testProp = "expando testProp Text";
engine.AddHostObject("expandoObj", expandoObj);

var propertyBag = new PropertyBag();
propertyBag["testProp"] = "property bag testProp Text";
engine.AddHostObject("propertyBagObj", propertyBag);

engine.Execute(@"Console.WriteLine('expandoObj.testProp=' + expandoObj.testProp);");
engine.Execute(@"Console.WriteLine('propertyBagObj.testProp=' + propertyBagObj.testProp);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in propertyBagObj) Console.WriteLine('propertyBagObj[' + item + ']=' + propertyBagObj[item]);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in expandoObj) Console.WriteLine('expandoObj[' + item + ']=' + expandoObj[item]);");

}

```

Edited Issue: [BUG] JScript for..in loop fails in Standards Mode [94]

$
0
0
It appears that the for/in loop is not working when JScript engine is initialized with WindowsScriptEngineFlags.EnableStandardsMode flag.

I tried adding PropertyBag and ExpandoObject as host objects.

I noticed that there is a ScriptEngineException when executing for/in loop on either of the two objects which has HResult of 0x800a0005 (Invalid procedure call or argument).

Without WindowsScriptEngineFlags.EnableStandardsMode flag everything works without exceptions.

I am developing on Windows 10 with ClearScript 5.4.3

Here is the sample program:

```
static void Main(string[] args)
{
var engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
engine.AddHostType("Console", typeof(Console));

dynamic expandoObj = new ExpandoObject();
expandoObj.testProp = "expando testProp Text";
engine.AddHostObject("expandoObj", expandoObj);

var propertyBag = new PropertyBag();
propertyBag["testProp"] = "property bag testProp Text";
engine.AddHostObject("propertyBagObj", propertyBag);

engine.Execute(@"Console.WriteLine('expandoObj.testProp=' + expandoObj.testProp);");
engine.Execute(@"Console.WriteLine('propertyBagObj.testProp=' + propertyBagObj.testProp);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in propertyBagObj) Console.WriteLine('propertyBagObj[' + item + ']=' + propertyBagObj[item]);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in expandoObj) Console.WriteLine('expandoObj[' + item + ']=' + expandoObj[item]);");

}

```

New Post: for/in loop in JScript standards mode

$
0
0
ClearScript wrote:
Hi again,

We have a set of Javascripts that work with Google Chrome and Firefox and we would rather not modify them with non-standard code.

Just curious, why are you using JScript? V8 provides much better performance and Chrome compatibility, and it isn't affected by the issue you discovered.

One concern is licensing. It may be difficult to get it approved.

New Post: Question about passing generic List.

$
0
0
I am trying to convert an C# application that used VSA JScript engine to use ClearScript with V8 engine. I have a question about how ClearScript handles generic list. I have the follow sample code:
    public class Item { public int Value; }
    public IList<Item> MyList = new List<Item>() { new Item(), new Item(), new Item() };

    void ClearScriptTest(object sender, EventArgs e) {
        using (var engine = new V8ScriptEngine()) {
            engine.AddHostObject("Me", this);
            engine.Execute("Me.MyList[0].Value = 123;");
            MessageBox.Show(MyList[0].Value.ToString());
        }
    }
When I run this code, an exception "TypeError: Cannot set property 'Value' of undefined"
will be thrown. However when I change the declaration type of MyList from IList<int> to List<int>, then the code works. It looks like that engine.Execute() uses the static declaration type instead of the actual type of the object Me.MyList. Is this a defect ? The old VSA JScript engine behaviors differently. Is there a way to configure ClearScript to fix this problem?

New Post: Question about passing generic List.

$
0
0
Hello!

Here's what's going on. In your script code, the expression Me.MyList is of the managed type IList<Item>. This type has an indexer that is actually an indexed property named "Item". ClearScript supports indexed properties, but it requires the following syntax:
// JavaScriptvar value = Me.MyList.Item.get(index); // or Me.MyList.Item(index)
Me.MyList.Item.set(index, value);
When you change the type to List<Item>, you enable ClearScript's special treatment of objects that implement IList. This feature supports array-like access from script code:
// JavaScriptvar value = Me.MyList[index];
Me.MyList[index] = value;
Note that IList<T> is not derived from IList and therefore doesn't trigger this feature.

It looks like that engine.Execute() uses the static declaration type instead of the actual type of the object Me.MyList. Is this a defect ?

No, this is by design. ClearScript's goal is to provide C#-like access to .NET types. .NET supports things like generic and overloaded methods, and C# method binding relies on static analysis of the method arguments. Script languages don't support static typing, so ClearScript simulates it with a feature called type restriction, which allows C#-like method binding to take place at runtime.

Is there a way to configure ClearScript to fix this problem?

You can use ClearScript's ScriptMemberAttribute to expose the runtime type of a given member:
[ScriptMember(ScriptMemberFlags.ExposeRuntimeType)]
public IList<Item> MyList = new List<Item> { new Item(), new Item(), new Item() };
You can also use the engine's DisableTypeRestriction property to turn off type restriction globally, but doing so can break some method invocation scenarios.

Good luck!

New Post: Question about passing generic List.

$
0
0
Thanks you so much for the quick replay. It is exactly what I was looking for!

Since we use JavaScript interface for less trained end-users, we really
prefer the relaxed and forgiving behavior. I hope the flag DisableTypeRestriction
won't be deprecated in the future.

It looks like that the C# class String is treated specially. Even with DisableTypeRestriction enabled,
methods of String class, like EndsWith(), are not exposed to script interface. Is there a general way
to enable such run-time type methods?

Another similar issue I encountered is that when a C# method expects an argument,
but when it is called in a script without argument, the script execution will fail with an exception.
The old VSA JScript engine will call the method with default values (like null or 0). Is there a general
property in ClearScript that enable such auto-argument-filling feature?

New Post: How to pass short int from script to C# methods

$
0
0
I have the following code that fails with an exception:
    short myValue;
    public void SetValue(short v) {
        myValue = v;
    }
    void ClearScriptTest2(object sender, EventArgs e) {
        using (var engine = new V8ScriptEngine()) {
            engine.AddHostObject("Me", this);
            engine.Execute("Me.SetValue(123);");
            MessageBox.Show(myValue.ToString());
        }
    }
When I change the type of the parameter, v, for SetValue() from short to int, the code works.
It looks like Me.SetValue() expects a value of short type. So, my
question is: How do I call a method in script with parameter with type of short? Is there a way to let the script engine to convert a constant like "123" automatically to short?

New Post: Question about passing generic List.

$
0
0
Hi again,

It looks like that the C# class String is treated specially. Even with DisableTypeRestriction enabled, methods of String class, like EndsWith(), are not exposed to script interface. Is there a general way to enable such run-time type methods?

Strings and numbers are just about the only objects for which ClearScript performs automatic data conversion. For more information, see here.

Another similar issue I encountered is that when a C# method expects an argument, but when it is called in a script without argument, the script execution will fail with an exception. The old VSA JScript engine will call the method with default values (like null or 0). Is there a general property in ClearScript that enable such auto-argument-filling feature?

No, ClearScript does not support automatic argument filling, as its method binding algorithm is based on an analysis of the argument types. However, it does support default arguments, so if you're designing the API being exposed to the script engine, you can specify default arguments as necessary to provide similar flexibility.

Cheers!

New Post: How to pass short int from script to C# methods

$
0
0
Hi James2015Li,

The native value of a JavaScript number is double-precision floating-point. When you pass such a value to a .NET method, ClearScript converts it to one of the following managed types, choosing the first one that results in no numeric data loss:
  • System.Int32
  • System.Int64
  • System.Single
  • System.Double
In your sample above the argument 123 is converted to System.Int32, which is not implicitly convertible to System.Int16, so the call fails. However, ClearScript provides a helper function you can use in this scenario:
engine.AddHostObject("host", new HostFunctions());
engine.Execute("Me.SetValue(host.toInt16(123));");
The HostFunctions class includes methods for converting script numbers to most managed numeric types. Unfortunately at the moment there's no way to change the default conversion algorithm.

Good luck!

Commented Issue: [BUG] JScript for..in loop fails in Standards Mode [94]

$
0
0
It appears that the for/in loop is not working when JScript engine is initialized with WindowsScriptEngineFlags.EnableStandardsMode flag.

I tried adding PropertyBag and ExpandoObject as host objects.

I noticed that there is a ScriptEngineException when executing for/in loop on either of the two objects which has HResult of 0x800a0005 (Invalid procedure call or argument).

Without WindowsScriptEngineFlags.EnableStandardsMode flag everything works without exceptions.

I am developing on Windows 10 with ClearScript 5.4.3

Here is the sample program:

```
static void Main(string[] args)
{
var engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
engine.AddHostType("Console", typeof(Console));

dynamic expandoObj = new ExpandoObject();
expandoObj.testProp = "expando testProp Text";
engine.AddHostObject("expandoObj", expandoObj);

var propertyBag = new PropertyBag();
propertyBag["testProp"] = "property bag testProp Text";
engine.AddHostObject("propertyBagObj", propertyBag);

engine.Execute(@"Console.WriteLine('expandoObj.testProp=' + expandoObj.testProp);");
engine.Execute(@"Console.WriteLine('propertyBagObj.testProp=' + propertyBagObj.testProp);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in propertyBagObj) Console.WriteLine('propertyBagObj[' + item + ']=' + propertyBagObj[item]);");
engine.Execute(@"Console.WriteLine('');");
engine.Execute(@"for (var item in expandoObj) Console.WriteLine('expandoObj[' + item + ']=' + expandoObj[item]);");

}

```

Comments: The problem is that JScript in Standards Mode slightly extends/breaks the `IDispatchEx` contract in order to pass extra data to the host. The extra data consumes otherwise unused argument bitfields and confuses the CLR's `IDispatchEx` implementation. We're testing a fix that installs vtable thunks that clear out the errant bitfields before passing the arguments through. This also fixes host property deletion.

New Post: How to pass short int from script to C# methods

$
0
0
Thanks for the response. This is really a awkward limitation. I don't know any language that does not support such
conversion in a standard way. With the suggested work-around, every embedded script engine might have different
way to do conversion (since the name 'host' is implementation dependent.)

Anyway, I found it also strange that ClearScript do support some implicit conversion like the following code works just fine:
    public short MyValue;
    void ClearScriptTest2(object sender, EventArgs e) {
        using (var engine = new V8ScriptEngine()) {
            engine.AddHostObject("Me", this);
            engine.Execute("Me.MyValue = 123;");
            MessageBox.Show(MyValue.ToString());
        }
    }

New Post: How to pass short int from script to C# methods

$
0
0
Hi again,

This is really a awkward limitation. I don't know any language that does not support such conversion in a standard way.

The problem is the ambiguity created by bridging two dissimilar runtimes. JavaScript has no method overloading, so once you find the right method, you can coerce or fill in the arguments as necessary. The CLR is exactly the opposite; you need to examine the arguments to find (or even construct) the right method.

Suppose an instance of the following class is exposed to JavaScript:
publicclass Thing {
    publicvoid Foo(byte arg) {}
    publicvoid Foo(sbyte arg) {}
}
Which method should be called by the JavaScript expression thing.Foo(123)?

On the other hand, this is only a problem when overloaded or generic methods are involved. If we do maximum narrowing of numeric values by default, we may be able to cover more common scenarios without explicit conversion, but no algorithm will work as expected in every situation.

I found it also strange that ClearScript do support some implicit conversion

.NET fields and (normal) properties can't be generic or overloaded, so there's no ambiguity. The type of a field or property is always known, so ClearScript can always make an attempt to convert the argument to the correct type.

Thanks!

New Post: How to pass short int from script to C# methods

$
0
0
Which method should be called by the JavaScript expression thing.Foo(123)?
Ideally the engine should try to find Foo(int arg); then Foo(short arg), Foo(byte arg), Foo(sbyte), till it finds a match. I guess C/C++ uses this kind of promotion chain.
.NET fields and (normal) properties can't be generic or overloaded, so there's no ambiguity. The type of a field or property is always known, so ClearScript can always make an attempt to convert the argument to the correct type.
Unfortunately, the above sample code fails when you change the data type from "short" to "float":
public float MyValue;
void ClearScriptTest2(object sender, EventArgs e) {
    using (var engine = new V8ScriptEngine()) {
        engine.AddHostObject("Me", this);
        engine.Execute("Me.MyValue = 123.45;");
        MessageBox.Show(MyValue.ToString());
    }
}

New Post: How to pass short int from script to C# methods

$
0
0
Hi James2015Li,

Based on your comments, we've taken a closer look and decided to make some changes.

Ideally the engine should try to find Foo(int arg); then Foo(short arg), Foo(byte arg), Foo(sbyte), till it finds a match. I guess C/C++ uses this kind of promotion chain.

ClearScript uses the actual C# invocation binder (part of the C# compiler) to provide access to .NET methods using rules that are documented and well-understood. As you've discovered, however, some ambiguity and suboptimal behavior exists when numeric arguments are passed from script code.

We've identified a bug in ClearScript that breaks some scenarios for integer arguments, and we'll fix it in the next point release. That should make your original sample above (with the short parameter) work as expected. Unfortunately there's no simple solution for single-precision floating-point parameters, so explicit conversion via host.toSingle() will continue to be required for float binding from JavaScript.

Unfortunately, the above sample code fails when you change the [field] data type from "short" to "float":

Yes, that's another bug. The next point release will relax the rules for numeric field and property assignment, allowing lossy conversion to take place implicitly.

Thank you very much for reporting these issues!

New Post: How to pass short int from script to C# methods

$
0
0
Thanks for the clarification. Just in the same venue, you probably can also enhance the handling of += operator for singles. With the current ClearScript version statement like "icon.position.x += 2.5" has to be expended to "icon.position.x = host.toSingle(icon.position.x + 2.5)".

New Post: Host objects that implement IExpando (IDispatchEx)

$
0
0
It looks like it is not possible to dynamically add properties from Javascript to host objects that implement IExpando interface (COM objects implementing IDispatchEx)

ClearScript is hitting the following in HostItem IExpando.AddField:
throw new NotSupportedException("Object does not support dynamic fields");
Am I missing something? If not, would this be something that will be implemented?

New Post: How to pass short int from script to C# methods

$
0
0
Hi again,

V8 doesn't allow hosts to alter the behavior of the arithmetic operators, but with the fix mentioned above no casting should be necessary in this situation.

Cheers!

New Post: Host objects that implement IExpando (IDispatchEx)

$
0
0
Hello,

That's correct; ClearScript doesn't provide dynamic exposure for IReflect/IExpando instances.

Questions:
  • What script engine(s) are you using?
  • Are these managed objects? Or do you need to expose native COM objects?
In any case, this isn't a scenario we've encountered before. If you need to get this working quickly, consider creating a wrapper that implements ClearScript's IPropertyBag or System.Dynamic.IDynamicMetaObjectProvider (or derives from System.Dynamic.DynamicObject).

Good luck!
Viewing all 2297 articles
Browse latest View live




Latest Images