In Javascript ES6, in the browser, I want to transfer custom class objects to a web worker using the "Transferable" interface. Is this possible? I can find documentation about this for ArrayBuffer objects, but not for custom class objects.
This is not a duplicate of How to pass custom class instances through Web-Workers? since my question is specifically about the Transferable interface. I want to pass my custom class instance to the worker without copying it.
I already addressed this question a few times, in different ways. I'm sorry, but the answer to your particular version of this inquiry is definitely no.
There are a few reasons for that.
Individual JavaScript objects are typically not allocated on continuous memory chunks (which would make it possible to transfer them in theory at least).
Any code that converts normal object/class to a ArrayBuffer would really just be overhead over the existing structured clone algorithm, that does the job well.
What you can do,
if you really want to which I'm not so sure you should.
Imagine a class like this:
class Vector2 {
constructor(existing) {
this._data = new Float64Array(2);
}
get x() {
return this._data[0];
}
set x(x) {
this._data[0] = x;
}
get y() {
return this._data[1];
}
set y(y) {
this._data[1] = y;
}
}
It's properties are stored in an array buffer and you can transfer it. But it's not much use yet, for it to work well, we need to make sure it can be constructed from received array buffer. That can be done for sure:
class Vector2 {
constructor(existing) {
if(existing instanceof ArrayBuffer) {
this.load(existing);
}
else {
this.init();
}
}
/*
* Loads from existing buffer
* #param {ArrayBuffer} existing
*/
load(existing) {
this._data = existing;
this.initProperties();
}
init() {
// 16 bytes, 8 for each Float64
this._data = new ArrayBuffer(16);
this.initProperties();
}
initProperties() {
this._coordsView = new Float64Array(this._data, 0, 2);
}
get x() {
return this._coordsView[0];
}
set x(x) {
this._coordsView[0] = x;
}
get y() {
return this._coordsView[1];
}
set y(y) {
this._coordsView[1] = y;
}
}
Now you can even subclass it, by passing larger array buffer from the subclass, where both parents and child's attributes will fit:
class Vector2Altitude extends Vector2 {
constructor(existing) {
super(existing instanceof ArrayBuffer ? existing : new ArrayBuffer(16 + 8));
this._altitudeView = new Float64Array(this._data, 16, 1);
}
get altitude() {
return this._altitudeView[0];
}
set altitude(alt) {
this._altitudeView[0] = alt;
}
}
A simple test:
const test = new Vector2();
console.log(test.x, test.y);
const test2 = new Vector2Altitude();
test2.altitude = 1000;
console.log(test2.x, test2.y, test2.altitude, new Uint8Array(test2._data));
To make some real use of it, you need to solve many other problems, and essentially implement your own memory allocation for complex objects.
Related
Is it possible to write a TypeScript Function which programmatically creates copies of an object, without hardcoding references to the object properties being copied?
I'm trying to enable a user workflow where the user is empowered to create copies of a specified object, i.e. create and partially complete one object using a Form, create 10x duplicates of the new object, fill-in data for new objects.
I've succeeded in creating a Function-Backed Action which duplicates a designated object, but all references to the properties being copied are hardcoded, which is less than ideal for maintenance and is a relatively common request for our org.
Code example for desired Function:
#OntologyEditFunction()
public GenerticBatchCopyObjects(mySelectedObject: ObjectAPIName, numberNewObjects: Integer): void {
/** Set UUID primary key */
let object_pk = Uuid.random()
for (let i = 1; i <= numberNewObjects; i++) {
/** initialize new object */
const newObject = Objects.create().ObjectAPIName(object_pk + "_" + String(i))
/** copy all properties from selected object record to new object */
for property in mySelectedObject.properties:
if property != "name_of_primary_key_column":
newObject.property = mySelectedObject.property
}
}
There’s not really a nice way to achieve this currently and it’s maybe not advised. This is primarily because the list of properties that will be copied from an object are fixed at publish-/compile-time in any (nice) method I can see.
Partial type-safe solution for copying properties only
I've included the most generic version of this function I can construct below, but it has some limitations. More concretely, the copy function
does not copy links that aren't represented by FK properties (i.e. it only copies properties);
does not adapt and might break when there are new or removed properties; and
is not easily maintained as functionality can change depending on when it is compiled.
private isPrimaryKey(x: string): x is MyObjectType["primaryKey"]["apiName"] {
return x === MyObjectType.primaryKey.apiName;
}
#OntologyEditFunction()
public copy(obj: MyObjectType): void {
const new_obj = Objects.create().myObjectType(Uuid.random());
var prop : keyof typeof MyObjectType.properties;
for (prop in MyObjectType.properties) {
if (!this.isPrimaryKey(prop)) {
new_obj[prop] = obj[prop];
}
}
}
Explicit type-safe solution for copying everything
The approach below requires more manual adjustment if the ontology changes, but makes it explicit that the code must be changed in line with ontology changes. This approach also copies links.
It is also worth noting that this behaviour may not be desired behaviour because it doesn't recursively copy the linked objects and instead attempts to copy the links. Please test that this gives the desired results.
static PROPERTIES = ["myProperty"] as const;
static MULTILINKS = ["myMultiLink"] as const;
static SINGLELINKS = ["mySingleLink", "myOtherSingleLink"] as const;
#OntologyEditFunction()
public copy2(obj: MyObjectType): void {
const new_obj = Objects.create().myObjectType(Uuid.random());
MyFunctions.PROPERTIES.forEach(p => {
new_obj[p] = obj[p];
});
MyFunctions.MULTILINKS.forEach(p => {
obj[p].all().forEach(v => new_obj[p].add(v));
});
MyFunctions.SINGLELINKS.forEach(p => {
const v = obj[p].get();
if (v !== undefined) {
new_obj[p].set(v);
}
});
}
You may need to exclude some of the code if your object type does not have properties/multi-links/single-links to make the compiler happy.
Is there a way to return several values in a function return statement (other than returning an object) like we can do in Go (or some other languages)?
For example, in Go we can do:
func vals() (int, int) {
return 3, 7
}
Can this be done in Dart? Something like this:
int, String foo() {
return 42, "foobar";
}
Dart doesn't support multiple return values.
You can return an array,
List foo() {
return [42, "foobar"];
}
or if you want the values be typed use a Tuple class like the package https://pub.dartlang.org/packages/tuple provides.
See also either for a way to return a value or an error.
I'd like to add that one of the main use-cases for multiple return values in Go is error handling which Dart handle's in its own way with Exceptions and failed promises.
Of course this leaves a few other use-cases, so let's see how code looks when using explicit tuples:
import 'package:tuple/tuple.dart';
Tuple2<int, String> demo() {
return new Tuple2(42, "life is good");
}
void main() {
final result = demo();
if (result.item1 > 20) {
print(result.item2);
}
}
Not quite as concise, but it's clean and expressive code. What I like most about it is that it doesn't need to change much once your quick experimental project really takes off and you start adding features and need to add more structure to keep on top of things.
class FormatResult {
bool changed;
String result;
FormatResult(this.changed, this.result);
}
FormatResult powerFormatter(String text) {
bool changed = false;
String result = text;
// secret implementation magic
// ...
return new FormatResult(changed, result);
}
void main() {
String draftCode = "print('Hello World.');";
final reformatted = powerFormatter(draftCode);
if (reformatted.changed) {
// some expensive operation involving servers in the cloud.
}
}
So, yes, it's not much of an improvement over Java, but it works, it is clear, and reasonably efficient for building UIs. And I really like how I can quickly hack things together (sometimes starting on DartPad in a break at work) and then add structure later when I know that the project will live on and grow.
Create a class:
import 'dart:core';
class Tuple<T1, T2> {
final T1 item1;
final T2 item2;
Tuple({
this.item1,
this.item2,
});
factory Tuple.fromJson(Map<String, dynamic> json) {
return Tuple(
item1: json['item1'],
item2: json['item2'],
);
}
}
Call it however you want!
Tuple<double, double>(i1, i2);
or
Tuple<double, double>.fromJson(jsonData);
You can create a class to return multiple values
Ej:
class NewClass {
final int number;
final String text;
NewClass(this.number, this.text);
}
Function that generates the values:
NewClass buildValues() {
return NewClass(42, 'foobar');
}
Print:
void printValues() {
print('${this.buildValues().number} ${this.buildValues().text}');
// 42 foobar
}
The proper way to return multiple values would be to store those values in a class, whether your own custom class or a Tuple. However, defining a separate class for every function is very inconvenient, and using Tuples can be error-prone since the members won't have meaningful names.
Another (admittedly gross and not very Dart-istic) approach is try to mimic the output-parameter approach typically used by C and C++. For example:
class OutputParameter<T> {
T value;
OutputParameter(this.value);
}
void foo(
OutputParameter<int> intOut,
OutputParameter<String>? optionalStringOut,
) {
intOut.value = 42;
optionalStringOut?.value = 'foobar';
}
void main() {
var theInt = OutputParameter(0);
var theString = OutputParameter('');
foo(theInt, theString);
print(theInt.value); // Prints: 42
print(theString.value); // Prints: foobar
}
It certainly can be a bit inconvenient for callers to have to use variable.value everywhere, but in some cases it might be worth the trade-off.
Dart is finalizing records, a fancier tuple essentially.
Should be in a stable release a month from the time of writing.
I'll try to update, it's already available with experiments flags.
you can use dartz package for Returning multiple data types
https://www.youtube.com/watch?v=8yMXUC4W1cc&t=110s
you can use Set<Object> for returning multiple values,
Set<object> foo() {
return {'my string',0}
}
print(foo().first) //prints 'my string'
print(foo().last) //prints 0
In this type of situation in Dart, an easy solution could return a list then accessing the returned list as per your requirement. You can access the specific value by the index or the whole list by a simple for loop.
List func() {
return [false, 30, "Ashraful"];
}
void main() {
final list = func();
// to access specific list item
var item = list[2];
// to check runtime type
print(item.runtimeType);
// to access the whole list
for(int i=0; i<list.length; i++) {
print(list[i]);
}
}
I have a ASP.NET WebApi project that I am working on. The boss would like the returns to support "partial response", meaning that though the data model might contain 50 fields, the client should be able to request specific fields for the response. The reason being that if they are implementing for example a list they simply don't need the overhead of all 50 fields, they might just want the First Name, Last Name and Id to generate the list. Thus far I have implemented a solution by using a custom Contract Resolver (DynamicContractResolver) such that when a request comes in I am peeking into it through a filter (FieldListFilter) in the OnActionExecuting method and determining if a field named "FieldList" is present and then if it is I am replacing the current ContractResolver with a new instance of my DynamicContractResolver and I pass the fieldlist to the constructor.
Some sample code
DynamicContractResolver.cs
protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
{
List<String> fieldList = ConvertFieldStringToList();
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
if (fieldList.Count == 0)
{
return properties;
}
// If we have fields, check that FieldList is one of them.
if (!fieldList.Contains("FieldList"))
// If not then add it, FieldList must ALWAYS be a part of any non null field list.
fieldList.Add("FieldList");
if (!fieldList.Contains("Data"))
fieldList.Add("Data");
if (!fieldList.Contains("FilterText"))
fieldList.Add("FilterText");
if (!fieldList.Contains("PageNumber"))
fieldList.Add("PageNumber");
if (!fieldList.Contains("RecordsReturned"))
fieldList.Add("RecordsReturned");
if (!fieldList.Contains("RecordsFound"))
fieldList.Add("RecordsFound");
for (int ctr = properties.Count-1; ctr >= 0; ctr--)
{
foreach (string field in fieldList)
{
if (field.Trim() == properties[ctr].PropertyName)
{
goto Found;
}
}
System.Diagnostics.Debug.WriteLine("Remove Property at Index " + ctr + " Named: " + properties[ctr].PropertyName);
properties.RemoveAt(ctr);
// Exit point for the inner foreach. Nothing to do here.
Found: { }
}
return properties;
}
FieldListFilter.cs
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
// We need to determine if there is a FieldList property of the model that is being used.
// First get a reference to the model.
var modelObject = actionContext.ActionArguments.FirstOrDefault().Value;
string fieldList = string.Empty;
try
{
// Using reflection, attempt to get the value of the FieldList property
var fieldListTemp = modelObject.GetType().GetProperty("FieldList").GetValue(modelObject);
// If it is null then use an empty string
if (fieldListTemp != null)
{
fieldList = fieldListTemp.ToString();
}
}
catch (Exception)
{
fieldList = string.Empty;
}
// Update the global ContractResolver with the fieldList value but for efficiency only do it if they are not the same as the current ContractResolver.
if (((DynamicContractResolver)GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver).FieldList != fieldList)
{
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DynamicContractResolver(fieldList);
}
}
I can then send a request with the json content payload looking as such:
{
"FieldList":"NameFirst,NameLast,Id",
"Data":[
{
"Id":1234
},
{
"Id":1235
}
]
}
and I will receive a response like so:
{
"FieldList":"NameFirst,NameLast,Id",
"Data":[
{
"NameFirst":"Brian",
"NameLast":"Mueller",
"Id":1234
},
{
"NameFirst":"Brian",
"NameLast":"Mueller",
"Id":1235
}
]
}
I believe that using the ContractResolver might run into threading issues. If I change it for one request is it going to be valid for all requests thereafter until someone changes it on another request (seems so through testing) If that is the case, then I don't see the usefulness for my purpose.
In summary, I am looking for a way to have dynamic data models such that the output from a request is configurable by the client on a request by request basis. Google implements this in their web api and they call it "partial response" and it works great. My implementation works, to a point but I fear that it will be broken for multiple simultaneous requests.
Suggestions? Tips?
A simpler solution that may work.
Create a model class with all 50 members with nullable types.
Assign values to the requested members.
Just return the result in the normal way.
In your WebApiConfig.Register() you must set the null value handling.
config.Formatters.JsonFormatter.SerializerSettings =
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
You must not touch the configuration. You need the contract resolver on per-request basis. You can use it in your action method like this.
public class MyController : ApiController
{
public HttpResponseMessage Get()
{
var formatter = new JsonMediaTypeFormatter();
formatter.SerializerSettings.ContractResolver =
new DynamicContractResolver(new List<string>()
{"Id", "LastName"}); // you will get this from your filter
var dto = new MyDto()
{ FirstName = "Captain", LastName = "Cool", Id = 8 };
return new HttpResponseMessage()
{
Content = new ObjectContent<MyDto>(dto, formatter)
};
// What goes out is {"LastName":"Cool","Id":8}
}
}
By doing this, you are locking yourself into JSON content type for response messages but you have already made that decision by using a Json.NET specific feature. Also, note you are creating a new JsonMediaTypeFormatter. So, anything you configure to the one in the configuration such as media type mapping is not going to be available with this approach though.
I know this question is from many years ago, but if you're looking to do this with modern releases of the framework, I'd recommend nowadays to use OData services (http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/using-select-expand-and-value).
Is it possible to use a simple action method - just like with Caliburn.Micro - instead of a command with MvvmCross bindings?
Example:
public void Action()
{
Tip = 11;
}
<Button
android:text="Button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/button1"
local:MvxBind="Click Action" />
It doesn't work out of the box, I tested that.
While I found a lot of samples about adding new target bindings, I didn't find a single one about adding a new source binding.
UPDATE:
This works now out of the box with the Rio binding. To use it, add the MvvmCross MethodBinding NuGet package to the Android project.
Up until now, much of the emphasis for MvvmCross has been on allowing multi-platform target binding with the source remaining mainly 'vanilla' INotifyPropertyChanged.
There have been some deviation in terms of ViewModel structure - e.g.:
the MvxCommandCollection - http://slodge.blogspot.co.uk/2013/03/fixing-mvvm-commands-making-hot-tuna.html
some users using Fody - http://twincoders.com/blog/codigo-limpio-con-fody/
Recently, several new feature requests have also been logged in this area:
AutoCommands - I think this is what you are asking about here - https://github.com/slodge/MvvmCross/issues/301
Rio binding sources - https://github.com/slodge/MvvmCross/issues/299
Tibet binding - https://github.com/slodge/MvvmCross/issues/298
Because of these, I do expect more functionality to be exposed in this area in the future...
With that said, if you wanted to get this working today, then MvvmCross Binding is overrideable so you could fairly easily do it:
1. Implement an ICommand that invokes a MethodInfo using reflection (for completeness this should probably also use a parameter if available) - some kind of InvokeMethodCommand (code for this left to the reader!)
.
2. Implement an MyMethodSourceBinding class which wraps the InvokeMethodCommand - something like:
public class MyMethodSourceBinding : MvxSourceBinding
{
private readonly MethodInfo _methodInfo;
protected MyMethodSourceBinding(object source, MethodInfo methodInfo)
: base(source)
{
_methodInfo = _methodInfo;
}
public override void SetValue(object value)
{
// do nothing - not allowed
}
public override Type SourceType
{
get { return typeof(ICommand); }
}
public override bool TryGetValue(out object value)
{
value = new InvokeMethodCommand(source, _methodInfo);
return true;
}
}
3. Override MvvmCross's registered IMvxSourceBindingFactory with your own implementation that can detect when a method is present - sadly most of this is cut and paste coding today - it would be something like
public class MySourceBindingFactory
: IMvxSourceBindingFactory
{
private IMvxSourcePropertyPathParser _propertyPathParser;
private IMvxSourcePropertyPathParser SourcePropertyPathParser
{
get
{
if (_propertyPathParser == null)
{
_propertyPathParser = Mvx.Resolve<IMvxSourcePropertyPathParser>();
}
return _propertyPathParser;
}
}
public IMvxSourceBinding CreateBinding(object source, string combinedPropertyName)
{
var tokens = SourcePropertyPathParser.Parse(combinedPropertyName);
return CreateBinding(source, tokens);
}
public IMvxSourceBinding CreateBinding(object source, IList<MvxPropertyToken> tokens)
{
if (tokens == null || tokens.Count == 0)
{
throw new MvxException("empty token list passed to CreateBinding");
}
var currentToken = tokens[0];
if (tokens.Count == 1)
{
return CreateLeafBinding(source, currentToken);
}
else
{
var remainingTokens = tokens.Skip(1).ToList();
return CreateChainedBinding(source, currentToken, remainingTokens);
}
}
private static MvxChainedSourceBinding CreateChainedBinding(object source, MvxPropertyToken propertyToken,
List<MvxPropertyToken> remainingTokens)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerChainedSourceBinding(source, (MvxIndexerPropertyToken) propertyToken,
remainingTokens);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
return new MvxSimpleChainedSourceBinding(source, (MvxPropertyNamePropertyToken) propertyToken,
remainingTokens);
}
throw new MvxException("Unexpected property chaining - seen token type {0}",
propertyToken.GetType().FullName);
}
private static IMvxSourceBinding CreateLeafBinding(object source, MvxPropertyToken propertyToken)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerLeafPropertyInfoSourceBinding(source, (MvxIndexerPropertyToken) propertyToken);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
//**************************
// Special code is here
var propertyToken = (MvxPropertyNamePropertyToken) propertyToken;
if (source != null)
{
var method = source.GetType().GetMethod(propertyToken.PropertyName, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
return new MyMethodSourceBinding(source, method);
}
}
return new MvxSimpleLeafPropertyInfoSourceBinding(source,
(MvxPropertyNamePropertyToken) propertyToken);
// Special code ends here
//**************************
}
else if (propertyToken is MvxEmptyPropertyToken)
{
return new MvxDirectToSourceBinding(source);
}
throw new MvxException("Unexpected property source - seen token type {0}", propertyToken.GetType().FullName);
}
}
4. Supply this source binding factory in your own custom binding builder - e.g.:
public class MyAndroidBindingBuilder
: MvxAndroidBindingBuilder
{
protected override IMvxSourceBindingFactory CreateSourceBindingFactory()
{
return new MvxSourceBindingFactory();
}
}
5. Supply this binding builder during your setup
public class Setup : MvxAndroidSetup
{
// ....
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new MyAndroidBindingBuilder();
}
}
Note: This approach is only for advanced users right now... As suggested in the first part of this question, I do expect the code in this area to change quite a lot so you might also encounter some issues maintaining a fork in this area. (Indeed the code in this area has already changed quite significantly on the Tibet Binding branch within the GitHub repo!)
I am iterating over the properties of various mapped tables in my code and need to know whether or not each property is lazy loaded. I have found that the instance variable used for storage, denoted by the Storage attribute on the property, will be of type System.Data.Linq.Link.
Is there a way that I can leverage these two facts at runtime to solve this problem?
Code:
public void LazyLoad(Type tableType)
{
foreach (var prop in tableType.GetGenericArguments()[0].GetProperties())
{
if (/* IS LAZY LOADED */)
{
//real work here...
Console.WriteLine(prop.Name);
}
}
}
The mappings look like this:
public partial class Address
{
private System.Data.Linq.Link<string> _City;
[Column(Storage="_City", DbType="...")]
public string City
{
get { /* ... */ }
set { /* ... */ }
}
}
You are almost there. Just a spoon full of reflection helps the medicine go down ;-)
private static bool IsLazyLoadedProperty(PropertyInfo property)
{
var column = property.GetCustomAttributes(typeof(ColumnAttribute), true)[0]
as ColumnAttribute;
var field = property.DeclaringType.GetField(column.Storage,
BindingFlags.Instance | BindingFlags.NonPublic);
if (!field.FieldType.IsGenericType)
{
return false;
}
return field.FieldType.GetGenericTypeDefinition() == typeof(Link<>);
}