Glossary: What I mean by multilevel Symbol is something that is like #Dummy.bar instead of single level like #bar. Dont know what is better name for it, sorry.
Symbols are very nifty. I can do:
class Foo {
static String hello() => "Said hello!";
}
ClassMirror clMir = reflectType(Foo) as ClassMirror();
print(clMir.invoke(#hello, []));
It prints Said hello!. Great!
But one cant do:
class Bar{
static final Bar bar = new Bar();
}
ClassMirror clMir = reflectType(Bar) as ClassMirror();
print(clMir.invoke(#bar.hello, []));
This would fail.
Also, I haven't found a place where you can get reflection for multilevel Symbol, like reflectSymbol(#Dummy.bar) and get InstanceMirror for bar or something similar.
So are there use cases for multilevel Symbols?
There are different use-cases.
Primarily, it represents a library name (library foo.bar.baz;). The mirror system uses it for that (see, e.g., https://api.dartlang.org/stable/1.20.1/dart-mirrors/MirrorSystem/findLibrary.html).
Secondarily, the mirror system is sometimes using it as a "qualified name" like library.name.ClassName.memberName to represent an exact class or library member (https://api.dartlang.org/stable/1.20.1/dart-mirrors/DeclarationMirror/qualifiedName.html).
It's not that useful outside of the mirror system.
Related
Lets say I want to refactor my code so it's easier to read and I have an object property that is type of Map<String,AnotherObject or dynamic> what is the best way to convert this property to another object? When it is a map I can call the relevant object using its String key. If it becomes another object how would I call the one I want?
for example:
class A1{
Map<String,B1> property;
}
to:
class A1{
List<B2> property;
}
class B2{
String key;
B1 property;
}
In the example above in order to get the property I want I would have to filter the list where key = keyIwant, while if it is a map I can just call map[key]. Is there any effective way to convert a map to an object? Dart is the technology I use.
I suppose you're trying to make your code more maintainable by replacing your current Map with something else, which you refer to as object.
I also suppose that by object you mean Dart classes with typed fields.
If you want to continue to be able to find "objects" by their String names, you cannot avoid using a Map.
If the "keys" are all known at compile-time (ie. before your program actually runs) then you can used typed objects, which is what you should prefer as it makes reasoning and organizing code much easier.
Let's say you know that your Map will only ever have keys a and b with types A and B, respectively. Then you can replace your Map easily:
class A {}
class B {}
class MyClass {
final A a;
final B b;
MyClass(this.a, this.b);
}
Simple.
If some "keys" may not be present, just turn them into nullable values:
class A {}
class B {}
class MyClass {
final A? a;
final B? b;
// passing a or b is now optional!
MyClass({this.a, this.b});
}
If you don't know what the keys will be at all, then there's no way around using a Map. That's what they are for.
With Dart support for dynamic typing, you could "assume" certain keys will have certain types, though. So, while this is normally bad for code maintenance due to the impossibility to analyze this before the program runs (ie. it may crash at runtime), you could do something like this:
class Foo {
final String a;
Foo(this.a);
String toString() => 'Foo($a)';
}
class Bar {
final String a;
Bar(this.a);
String toString() => 'Bar($a)';
}
// example usage
void main() {
Map<String, dynamic> map = {'foo': Foo('a foo')};
Foo foo = map['foo'];
print(foo); // ok!
Bar? bar = map['bar'];
print(bar); // null
}
Hopefully this helps clarify when you should use an "object" and when you need to use a Map.
I am looking for a library or tools which offer functionality to build up a data structure which I can use to find variable or method declarations that are used in a class in another scope.
example code:
class A
{
public void methodA()
{
B external = new B();
external.methodB(); // I would like to know the name/location where this method is declared. something like: classB.java ... line 3
}
}
class B
{
public void methodB()
{
}
}`
Would Rascal be a good candidate to retrieve this kind of information? I have been using the tool before. As far as I know, I can create an AST but this will not have enough information to determine the scope of where certain variables/methods are declared.
If this would not be the right candidate, any ideas on alternatives? My list of candidates I am currently looking into are: Antlr/symtab; JavaParser/JavaSymbolSolver; Spoon; Rascal; JDT
Yes, there are certainly several options to find out where something is declared.
The first answer is to retrieve the decl information from any node in the AST like so, for example:
rascal>myTree.decl
loc: |java+parameter:///myClass/fac(int)/n|
From the location value you see that this is the parameter named n in the method named fac in the class myClass.
Now you can disect the location to go find the parent, using the access fields and function for locations, like myTree.decl.path etc, or you can find your information further in an M3 model which the AST builder can also construct:
model = createM3FromEclipseProject(|project://myProject);
This model contains relations like this: rel[loc, loc] containment, all defined here:
Core language model: https://github.com/usethesource/rascal/blob/master/src/org/rascalmpl/library/analysis/m3/Core.rsc
Java extensions: https://github.com/usethesource/rascal/blob/master/src/org/rascalmpl/library/lang/java/m3/Core.rsc
To find the parents in the containment relation you could try this:
model.containment[myTree.decl]
or this for the reverse lookup:
invert(model.containment)[myTree.decl]
For your particular question the rel[loc src, loc name] uses relation is also quite interesting which maps fully qualified declaration names to the source location uses, and rel[loc name, loc src] declarations which maps the qualified names to where they are declared.
For example, I'd like to just be able to write:
class Dog {
final String name;
Dog(this.name);
bark() => 'Woof woof said $name';
}
But have #Dog.bark's type definition be () => String.
This previously wasn't possible in Dart 1.x, but I'm hoping type inference can save the day and avoid having to type trivial functions where the return type is inferable (the same as it does for closures today?)
The language team doesn't currently have any plans to do inference on member return types based on their bodies. There are definitely cases like this where it would be nice, but there are other cases (like recursive methods) where it doesn't work.
With inference, we have to balance a few opposing forces:
Having smart inference that handles lots of different cases to alleviate as much typing pain as we can.
Having some explicit type annotations so that things like API boundaries are well-defined. If you change a method body and that changes the inferred return type, now you've made a potentially breaking change to your API.
Having a simple boundary between code that is inferred and code that is not so that users can easily reason about which parts of their code are type safe and which need more attention.
The case you bring up is right at the intersection of those. Personally, I lean towards not inferring. I like my class APIs to be pretty explicitly typed anyway, since I find it makes them easier to read and maintain.
Keep in mind that there are similar cases where inference does come into play:
Dart will infer the return type of an anonymous function based on its body. That makes things like lambdas passed to map() do what you want.
It will infer the return type of a method override from the method it is overriding. You don't need to annotate the return type in Beagle.bark() here:
class Dog {
String bark() => "Bark!";
}
class Beagle extends Dog {
final String name;
Dog(this.name);
bark() => 'Woof woof said $name';
}
I have a class with a large number of properties that map to some JSON data I've parsed into a Map object elsewhere. I'd like to be able to instantiate a class by passing in this map:
class Card {
String name, layout, mana_cost, cmc, type, rarity, text, flavor, artist,
number, power, toughness, loyalty, watermark, border,
timeshifted, hand, life, release_date, starter, original_text, original_type,
source, image_url, set, set_name, id;
int multiverse_id;
List<String> colors, names, supertypes, subtypes, types, printings, variations, legalities;
List<Map> foreign_names, rulings;
// This doesn't work
Card.fromMap(Map card) {
for (var key in card.keys) {
this[key] = card[key];
}
}
}
I'd prefer to not have to assign everything manually. Is there a way to do what I'm trying to do?
I don't think there is a good way to do it in the language itself.
Reflection would be one approach but it's good practice to avoid it in the browser because it can cause code bloat.
There is the reflectable package that limits the negative size impact of reflection and provides almost the same capabilities.
I'd use the code generation approach, where you use tools like build, source_gen to generate the code that assigns the values.
built_value is a package that uses that approach. This might even work directly for your use case.
I've recently been trying to learn the Object-Oriented aspects of F#, and have become curious about how to restrict access to types/modules in the language.
More specifically, I want to know the difference between writing this:
Example.fsi
module Stack =
val foo : string
Example.fs
module Stack =
let foo = "foo"
let bar = "bar"
and alternatively this:
module Stack =
let foo = "foo"
let private bar = "bar"
Do they not accomplish exactly the same thing in the end? Coming from a C# background, I'm much inclined just to use the access modifiers over signature (FSI) files. They seem to be more versatile (can apply to modules/types in namespaces, for example), whereas I don't any situation in which signature files offer something that access modifiers don't.
They accomplish almost the same thing. (Note that you can use an .fsi file for types in namespaces too, was unsure what your comment about that meant.)
A signature file has a couple advantages:
You can make entities public for the duration of the file, but then private to the subsequent files of the project.
You can have just your short summary in the signature file, so the public interface is easy to read without having to scan tons of code.
The first bullet is not to be trifled with - within-assembly encapsulation like this is actually a pretty huge feature for very large projects. Being able to define a few types which are public to one another within File1.fs, but then only have a subset of those types/methods be public to the rest (File2.fs, File3.fs, etc.) is quite useful (a little bit like 'friend' in C++).