I am working with a third party library from Kotlin and one of the things I must do is call delete thing[key] in order to remove an item from thing. I am unable to figure out how to do this from Kotlin code.
I did try js("delete thing[key]"), but thing is a parameter to a function and is name-mangled by the Kotlin > JavaScript compiler so an exception is thrown when the line is executed. I also tried js("delete ") thing[key] but unsurprisingly that didn't work either.
For delete operator You can write:
external fun delete(p: dynamic): Boolean = noImpl
//...
delete(thing[key])
For more convenient use I'd added some helpers:
fun delete(thing: dynamic, key: String) {
delete(thing[key])
}
// or
fun String.deleteFrom(d: dynamic) {
delete(d[this])
}
fun test(a: Any, k: String) {
delete(a, k)
k.deleteFrom(a)
k deleteFrom a
}
Note: using the delete operator is not a good practice and it'll leads to deoptimizations in JS VMs
Related
I have a Kotlin/JS project, using Kvision (I think started from a Kvision template)
My build.gradle.kts looks like this
https://ideone.com/yOEcMF
Questions:
How do I call from JS code a function defined by me in Kotlin?
Say I have this in .kt file :
package com.zzz
class KotlinHelper {
fun doXXX(str: String): Int = str.length
fun doYYY(bytes: ByteArray): String = bytes.decodeToString()
}
val kotlinHelper = KotlinHelper()
I want to call it from Javascript +/- like this
kotlinHelper.doXXX("something");
(the other way around I managed, meaning call from Kotlin code defined in JS - by use of "external" modifier on Kotlin class & actual implementation in JS)
Found this https://kotlinlang.org/docs/js-to-kotlin-interop.html .. but still didn't managed.
Can you explain how this works ?
My Kotlin code + whatever Kotlin + Kvision brings seem to get bundled & transpiled to Javascript in "main.bundle.js"
Code also seems obfuscated & minified.. I obviously want to call method with the name that I defined it have - is this possible?
Is the Kotlin code, that is not used - removed?
worked like this
Call from JS
new KTJS_Kvision.com.xxx.yyy.KotlinHelper().doXXX("Ana")
KTJS_Kvision - is my project name
com.xxx.yyy.KotlinHelper is the full name of class (incl packageName)
I also have these annotations:
#JsExport
class KotlinHelper {
#JsName("doXXX")
fun doXXX(str: String): Int = str.length
...
I am trying to add a toCamelCase function to the String prototype in React with TypeScript.
Here is what I did, in a toCamelCase.d.ts file:
interface String {
toCamelCase(): string;
}
String.prototype.toCamelCase = function (): string {
return this[0].toUpperCase() + this.slice(1).toLowerCase();
};
Now I am just wondering when and in which file should I load this script so I can get access to it.
I am aware that I can simply define a function and use that.
However, I am curious how to do it with prototype and what would be the downside doing things like this if there are any.
Where to do it?
In main.js or index.js or any other file that bootstraps your application
What are the downsides?
You can never know if one of the libraries that you use using relies on String.prototype being unaltered. It can cause major issues that you will have a hard time finding.
So I'm writing a compiler, and different "Statement" types have different classes. A Block Statement has a BlockStatement class, an If Statement has an IfStatement class, etc.
I need to be able to tell what type of object I'm working with at runtime, eg
class BlockStatement extends Statement {
constructor(...children: Statement[]) {
super()
this.rep.assemble(
new BlockLabel(),
children.map(child => Statement.extractRep(child))
)
}
private addToBlock(pos: number, s: Statement): void {
this.rep.addChild(pos, Statement.extractRep(s))
}
}
function prettyPrint(s: Statement) {
switch () {
case 'BlockStatement': {
}
}
}
How can I tell what type of Statement I am working with? And even if I can tell, will it not matter since it may slice any inherited functionality since the parameter is a statement?
###object###.constructor.name does the trick, however, ive heard minifying may cause issues with this. Then cast itself as whatever it is so intellisense works
This question comes in two parts. What I want to do is to put most of my program logic in c++ classes and some view related function in js (like DOM manipulation and styling.) I use emscripten embind the classes and it works fine while I don't know how to interact with the js code (there are really limited resources on their tutorial.)
I was thinking to pass a val object to the c++ class according to their tutorial (https://github.com/kripken/emscripten/wiki/Tutorial) The passing works just fine while the "call" function doesn't work. I got a compile time error.
Here is the example I tried which they put on their tutorial:
#include <emscripten/val.h>
using namespace emscripten;
int main(){
val Math = val::global("Math");
Math.call("abs",-10);
return 0;
}
and I got the following errors:
error: no matching member function for call to 'call'
Math.call("abs",-10);
~~~~^~~~
emscripten/1.5.6/system/include/emscripten/val.h:247:21: note: candidate template ignored: couldn't infer template argument 'ReturnValue'
ReturnValue call(const char* name, Args&&... args) const {
Basically it says the the compiler doesn't know the return type of the "call" function.
Did I do anything wrong or is there a better way to interact with js code?
Thanks,
yi
That's a common C++ problem. As a general rule, the following message should always make you double check in C++:
note: candidate template ignored: couldn't infer template argument 'ReturnValue' ReturnValue call(const char* name, Args&&... args) const
This mostly means that you tried to call a templated function but did not specify the necessary types.
If you look at the signature (in system/include/emscripten/val.h):
template<typename ReturnValue, typename... Args>
ReturnValue call(const char* name, Args&&... args) const
While it can infer Args quite fine, it has no idea, what ReturnValue might be. So calling this function should be done via e.g.:
Math.call<int>("abs",-10);
I am newbie in rhino.
Currently, I am using Rhino 1.7R framework thru .NET 4 and IKVM.NET.
I exposed several wrapped classes implementing NativeJavaObject using setWrapFractory() API.
public class InterceptNativeObject : NativeJavaObject
{
public InterceptNativeObject()
{
}
public override Object get(String name, Scriptable start)
{
Object res = base.get(name, start);
if (res is NativeJavaMethod)
{
NativeJavaMethod method = (NativeJavaMethod)res;
return new RhinoMethodWrapFunction(method);
}
if (res == org.mozilla.javascript.UniqueTag.NOT_FOUND &&
base.javaObject is IPropertBox && base.javaObject != null)
{
object ret = ((IPropertBox)base.javaObject)._x__GetPropertyValue(name);
return Utils.ConvertCLRValueToJavaValue(ret);
}
return res;
}
.....
}
Now, I can access all .NET methods and properties as I wanted.
My current problem is to support 'for...in' my NativeJavaObject classes.
When I evaluate
'for(var prop in myClass){printf(prop);};' ,
it returns 'no 'in' call for non-object' error.
It seems the 'get' attempting to searching an object of ' _iterator_', but it resulted in 'not found' at get() function. So, it ends up with exception.
So far, I tried
added java.util.iterator
return this.getIds().GetEnumrator();
None of works.
How can i allow property enumrate access for my Wrapped NativeJavaObject?
What is Rhino's expected return value of ' _iterator_' to enable 'for...in'?
Thanks in advance!
__iterator__ is part of a Mozilla specific language extension. That link explains that the __iterator__ method returns an object with a next method that throws StopIteration when the iterator is exhausted.
You have to opt in to iterators and generators though:
To enable JavaScript 1.7 support, you must set the version as 170 using the Context.setLanguageVersion() API call. If you are using the Rhino shell, you can specify -version 170 on the command line or call version(170) in code executed by the shell.
You can write JS in rhino that will wrap a Java iterator to present it as a JS iterator:
function javaIteratorToJsIterator(javaIterator) {
return {
next: function () {
if (!javaIterator.hasNext()) { throw StopIteration; }
return javaIterator.next();
}
};
}
Alternatively, you can use Mozilla style generators but I think you need to create the Rhino interpreter with an option to enable them.
While custom iterators are a useful tool, their creation requires careful programming due to the need to explicitly maintain their internal state. Generators provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function which can maintain its own state.
A generator is a special type of function that works as a factory for iterators. A function becomes a generator if it contains one or more yield expressions.