How haskell types are different than regular PHP classes.
If i disable extending can I simulate something similar in PHP or JavaScript.
Haskell:
data Person = Person { firstName :: String
, lastName :: String
, age :: Int
, height :: Float
, phoneNumber :: String
, flavor :: String
age :: Person -> Int
age (Person p) = p.age
newAge = age(Person {age:=35})
Js:
class Person {
constructor(data) {
this.data = data
}
}
function age(p) {
if (p instanceof Person) return p.age
}
let personAge = age(new Person({age: 35})); // 35
There can be syntax errors but ignore them.
In a nutshell if I dont use inheritance the js code is similar to Haskell's.
I dont have pattern matching but i can use "if instanceof " to check types.
Besides the confusion between type classes and data types, you may want to read OOP vs. Haskell type classes. Data types, which you use, behave much like immutable objects. So Haskell's
data Person = Person { age :: Int }
p1, p2 :: Person
p1 = Person { age = 35 }
p2 = p1 { age = age p1 + 1 }
might be written in ES6 like
class Person {
constructor(age) {
this.age = age;
}
}
p1 = new Person(35);
p2 = new Person(p1.age + 1);
In ES6 this does not guarantee against immutability, though. For that, see the const and ... keywords for merging the properties of objects without changing the original objects. The article discusses various other solutions but ends up suggesting:
const p1 = {
age: 35
}
const p2 = {
...p1,
age: p1.age + 1
}
Related
Let's have well known complex type (CT, e.g. Dto from the example).
Let's have set of type converters (functions) transforming value of one type to another (e.g. int SubDto2ToInt(SubDto2 sub), string GuidToString(Guid gd)).
Is there any method, how to configure Automapper and tell him:
"Map CT using these provided Type Converters and create object of anonymous type."?
This would effectively:
go over all CT's properties (recursively)
check the list of converters
if any present for given property type, convert and add to the result
otherwise proceed the default way (put it "as is" to the result)
I have had partial success when I pre-created the anonymous type, but that does not make much sense, because I can then create "normal" target type and define classic mapping. So the point is to let the Automapper create the target type on his own. The target member types would then be driven by either the source type or the conversion result type (if registered).
Example:
class SubDto1 { int M1; int M2; } // Pretend they are get/set properties
class SubDto2 { int N1; int N2; } // dtto
class Dto { SubDto1 Sub1; SubDto2 Sub2; Guid Id; } // dtto
var source = new Dto { Sub1 = new SubDto1 {M1 = 1, M2 = 2}, Sub2 = new SubDto2 {N1 = 10, N2 = 20}, Id = Guid.NewGuid()};
var expectedTargetEquivalentTo = new
{
Sub1 = new {M1 = 1, M1 = 2}, // No conversion registered here, "as is"
Sub2 = 30, // Fancy SubDto2 -> int conversion registered here
Id = "00000000-0000-0000-0000-000000000000", // Guid -> string conversion registered here
}
I'm trying to access a class value by using a variable previously defined in dart, but I keep getting the error the operator [] isn't defined for the class
In Javascript I would access an object value using a variable like this:
let movie = {
movieTitle : 'Toy Story',
actor: 'Tom Hanks'
}
let actorName = 'actor';
console.log(movie[actorName]); // <- what I'm trying to replicate in dart
// expected output: Tom Hanks
Here is what I've tried and is throwing that error
class Movie {
String name;
String actor;
String producer;
}
void main() {
var movieTitle = new Movie();
movieTitle.name = 'Toy Story';
movieTitle.actor = 'Tom Hanks';
print(movieTitle.actor); <- prints out Tom Hanks as expected
var actorName = 'actor';
print(movieTitle[actorName]); <- throws error
}
I expect to be able to use a variable on the fly to access the value.
A trivial use case for me would be if I had a a list of Movie classes, where some actors and producers are null, I would like to filter on either non null actors or producer with a function like so:
List values = movieList.where((i) => i.actor != "null").toList(); // returns all Movies in movieList where the actor value isn't the string "null"
var actorIsNull = 'actor';
List values = movieList.where((i) => i[actorisNull] != "null").toList(); // throws error
You can createn a toMap() function in your Movie class and access properties using [] operator
class Movie {
String name;
String actor;
String producer;
Map<String, dynamic> toMap() {
return {
'name': name,
'actor' : actor,
'producer' : producer,
};
}
}
Now Movie class properties can be accessed as:
Movie movie = Movie();
movie.toMap()['name'];
You cannot access class members by a string containing their name. (Except with mirrors - outside the scope of this answer.)
You could remove the class altogether and just use a Map<String, String>.
Map<String, String> movie = {
'movieTitle': 'Toy Story',
'actor': 'Tom Hanks',
}
You could add some bool methods on the class.
bool hasNoActor() => actor == null;
...
List values = movieList.where((m) => !m.hasNoActor()).toList();
Or, you could pass a lambda to your mapper.
Movie movieTitle = Movie()
..name = 'Toy Story'
..actor = 'Tom Hanks';
Function hasActor = (Movie m) => m.actor != null;
List values = movieList.where(hasActor).toList();
I need to retrieve the value from an annotation such as this one that uses a string constant:
#Component(property = Constants.SERVICE_RANKING + ":Integer=10")
public class NyServiceImpl implements MyService {
But I am getting a kind of K_UNKNOWN and the doc says "the value is an expression that would need to be further analyzed to determine its kind". My question then is how do I perform this analysis? I could even manage to accept getting the plain source text value in this case.
The other answer looks basically OK, but let me suggest a way to avoid using the internal class org.eclipse.jdt.internal.core.Annotation and its method findNode():
ISourceRange range = annotation.getSourceRange();
ASTNode annNode = org.eclipse.jdt.core.dom.NodeFinder.perform(cu, range);
From here on you should be safe, using DOM API throughout.
Googling differently I found a way to resolve the expression. Still open to other suggestions if any. For those who might be interested, here is a snippet of code:
if (valueKind == IMemberValuePair.K_UNKNOWN) {
Annotation ann = (Annotation)annotation;
CompilationUnit cu = getAST(ann.getCompilationUnit());
ASTNode annNode = ann.findNode(cu);
NormalAnnotation na = (NormalAnnotation)annNode;
List<?> naValues = na.values();
Optional<?> optMvp = naValues.stream()
.filter(val-> ((MemberValuePair)val).getName().getIdentifier().equals(PROPERTY))
.findAny();
if (optMvp.isPresent()) {
MemberValuePair pair = (MemberValuePair)optMvp.get();
if (pair.getValue() instanceof ArrayInitializer) {
ArrayInitializer ai = (ArrayInitializer)pair.getValue();
for (Object exprObj : ai.expressions()) {
Expression expr = (Expression)exprObj;
String propValue = (String)expr.resolveConstantExpressionValue();
if (propValue.startsWith(Constants.SERVICE_RANKING)) {
return true;
}
}
}
else {
Expression expr = pair.getValue();
String propValue = (String)expr.resolveConstantExpressionValue();
if (propValue.startsWith(Constants.SERVICE_RANKING)) {
return true;
}
}
}
//report error
}
private CompilationUnit getAST(ICompilationUnit compUnit) {
final ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(compUnit);
parser.setResolveBindings(true); // we need bindings later on
CompilationUnit unit = (CompilationUnit)parser.createAST(null);
return unit;
}
I want to narrow a string to a string literal union. In other words, I want to check if the string is one of the possible values of my literal union, so that this will work (if the operator couldbe existed).
type lit = "A" | "B" | "C";
let uni: lit;
let str = "B";
if(str couldbe lit){
uni = str;
} else {
doSomething(str);
}
How can I achieve this?
I tried using if (str instanceof lit), but that doesn't seem to work. Using keyof to iterate over the string union doesn't work either, because the allowed values aren't keys per se.
One way would be to use switch with one case for each possible value, but that could lead to subtle errors if lits allowed values change.
If you hate switch cases, as I do:
since TypeScript 3.4 – const assertions it's also possible to produce union type from array of your strings ^_^
const list = <const>["A", "B", "C"];
type Lit = typeof list[number]; // "A" | "B" | "C"
function isLit(str: string): str is Lit {
return !!lits.find((lit) => str === lit);
}
You can use User-Defined Type Guards.
type lit = "A" | "B" | "C";
let uni: lit;
let str = "B";
function isLit(str: string): str is lit {
return str == "A" || str == "B" || str == "C";
}
function doSomething(str: string) {
}
if (isLit(str)) {
uni = str;
}
else {
doSomething(str);
}
ADD:
To avoid duplicated edit, class can be used both for compile-time and run-time. Now all you have to do is to edit just one place.
class Lit {
constructor(public A = 0, public B = 0, public C = 0) {}
}
type lit = keyof Lit;
let uni: lit;
function isLit(str: string): str is lit {
let lit = new Lit();
return (str in lit) ? true : false;
}
This is my take on the problem with the type guard and with strictNullChecks turned off (this is limitation on a project; if this option is true TS will require exhaustiveness on the switch/case).
Line const _notLit: never = maybeLit; guaranties that when you change lit type you need to update the switch/case also.
Downside of this solution is that it gets very verbose as the union type lit grows.
type lit = "A" | "B" | "C";
function isLit(str: string): str is lit {
const maybeLit = str as lit;
switch (maybeLit) {
case "A":
case "B":
case "C":
return true;
}
// assure exhaustiveness of the switch/case
const _notLit: never = maybeLit;
return false;
}
If possible this task is more suitable for enum or if you require a type and don't mind creating underlying enum for checking, you can create type guard something like this:
enum litEnum {
"A",
"B",
"C",
}
type lit = keyof typeof litEnum;
function isLit(str: string): str is lit {
return litEnum[str] !== undefined;
}
You can also use a zod enum to do this:
import zod from 'zod'
const ColorMode = zod.enum(['light', 'dark', 'system'] as const)
let _mode = 'light' // type is string
let mode = ColorMode.parse(_mode) // type is "light" | "dark" | "system"
_mode = 'twilight'
mode = ColorMode.parse(_mode) // throws an error, not a valid value
You can also extract the type from the zod schema when needed:
type ColorMode = zod.infer<typeof ColorMode>
I find a validation library like this is the easiest and most robust way to parse, validate, and type-narrow variables/data when I would otherwise have to reach for manually-written and error-prone type guards/predicates.
Haxe seems to assume that certain things must be Int. In the following function,
class Main {
static function main() {
function mult_s<T,A>(s:T,x:A):A { return cast s*x; }
var bb = mult_s(1.1,2.2);
}
}
I got (with Haxe 3.01):
Main.hx:xx: characters 48-49 : mult_s.T should be Int
Main.hx:xx: characters 50-51 : mult_s.A should be Int
Can anyone please explain why T and A should be Int instead of Float?
A more puzzling example is this:
class Main {
public static function min<T:(Int,Float)>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //compile error
var b = min(1,2); //ok
}
}
I can't see why t<t2 implies that either t or t2 is Int. But Haxe seems prefer Int: min is fine if called with Int's but fails if called with Float's. Is this reasonable?
Thanks,
min<T:(Int,Float)> means T should be both Int and Float. See the constraints section of Haxe Manual.
Given Int can be converted to Float implicitly, you can safely remove the constraint of Int. i.e. the following will works:
http://try.haxe.org/#420bC
class Test {
public static function min<T:Float>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //ok
$type(a); //Float
trace(a); //1.1
var b = min(1,2); //ok
$type(b); //Int
trace(b); //1
}
}