Suppose:
var p = new ArgParser();
p.addOption('query');
Is there a way using ArgResults to determine whether user failed to supply --query argument without catching the ArgumentException?
$ dart myprogram.dart --query
Unhandled exception:
FormatException: Missing argument for "query".
I tried:
results['query'] != null
but get the same exception.
No. The ArgParser always throws a FormatException on parse when the user does not provide the expected arguments.
Related
I have a small helper proc that is supposed to tell me at compile-time whether a type is an object-type or not.
func isObject*[T](val: typedesc[T]): bool {.compileTime.} = T is (object or ref object)
However, when I call this proc with a simple echo to see whether it works, I receive an error:
type A = object
echo isObject(A)
Error: request to generate code for .compileTime proc: isObject
Why is that? It should be perfectly valid to just call this, isObject should just compile to true and in the end what's written there is echo true, why does this cause this cryptic error?
The problem here is that runtime code (The echo call) is trying to work with a compiletime proc.
That is not valid, as the compiler would not replace the function-call with its result, but try to actually call the function at runtime instead. The compiler knows this is invalid behaviour and thus prohibits it by throwing an error, albeit one that isn't that useful.
The only way this can be allowed is if you store the result of the compile-time proc in a compile-time variable, aka a const. These are allowed to be used at runtime.
So the calling code would look more like this instead:
type A = object
const x = isObject(A)
echo x
EDIT:
As Elegantbeef pointed out on nim's discord:
Another alternative is to just do what I thought would happen initially and have that isObject(A) call evaluate fully at compile-time, so that at runtime it goes away and all that's left is it's result, true.
To do so, just use static:
type A = object
echo static(isObject(A))
Can someone simply explain to me how null assertion (!) works and when to use it?
The ! operator can be used after any expression, e!.
That evaluates the expression e to value v, then checks whether v is the null value. If it is null, an error is thrown. If not, then e! also evaluates to v.
The static type of an expression e! is (basically) the static type of e with any trailing ?s remove. So, if e has type int?, the type of e! is int.
You should not use e! unless e can be null (the type of e is potentially nullable).
The ! operator is dynamically checked. It can throw at runtime, and there is no static check which can guarantee that it won't. It's like using a value with type dynamic in that all the responsibility of preventing it from throwing is on the author, the compiler can't help you, and you need good tests to ensure that it won't throw when it's not supposed to.
It's called an assertion because it should never throw in production code.
So, use e! when you know (for some reason not obvious to the compiler, perhaps because of some invariant guaranteeing that the value is not null while something else is true) that e is not null.
Example:
abstract class Box<T extends Object> {
bool hasValue;
T? get value;
}
...
Box<int> box = ...;
if (box.hasValue) {
var value = box.value!;
... use value ...
}
If you are repeatedly using ! on the same expression, do consider whether it's more efficient to read it into a local variable just once.
Also, if (like this Box example) the value being null is equivalent to the other test you just did, maybe just check that directly:
Box<int> box = ...;
var value = box.value;
if (value != null) {
... use value ...
}
This code, with an explicit != null check on a local variable, is statically guaranteed to not throw because the value is null.
The code using ! above relies on the author to maintain whichever invariant allowed them to write the !, and if something changes, the code might just start throwing at runtime. You can't tell whether it's safe just by looking at the code locally.
Use ! sparingly, just like the dynamic type and late declarations, because they're ways to side-step the compiler's static checking and ensure it that "this is going to be fine". That's a great feature when you need it, but it's a risk if you use it unnecessarily.
I have nested comments. In order to fetch them from JSON, I have the following fromJson() function:
Comment.fromJson(Map<String, dynamic> json)
: id = json['id'],
...
children = json['children'] != null
? json['children'].map((c) => Comment.fromJson(c)).toList()
: null,
...
This checks if the current comment has any children comments, and if so, recursively parses them from JSON into a Comment. However when I run this, I get the following error:
[ERROR:flutter/shell/common/shell.cc(214)]
Dart Unhandled Exception:
type 'List<dynamic>' is not a subtype of type 'List<Comment>'
stack trace: #0 new Comment.fromJson (package:app/models/comment.dart:43:18)
Which points to the line where I assign children with children = json.... I'm new to dart, but I don't understand how mapping over a list, and returning a Comment doesn't let Dart infer the type of the list. How do I fix this? Adding as List<Comment> after toList() didn't work. If I add as Comment after Comment.fromJson(c), I get unnecessary cast.
Dart can't infer anything from json['children'].map(...).toList() because json['children'] is of type dynamic, and therefore it doesn't know what the .map call is going to resolve to at runtime.
At runtime, since .map is called without an explicit type, it ends up being a call to .map<dynamic>(...), and then .toList() returns List<dynamic>.
Try either:
Explicitly using .map<Comment>(...).
Casting json['children']: (json['children'] as List<Map<String, dynamic>>).map(...). It'd probably be a good idea to validate this anyway.
Inside a controller i just test these two lines. RaceRegistration domain has a property compositeEvent. So, i access the Registration domain first and then access the compositeevent using .compositeEvent.
println (RaceRegistration.get(r.toLong()))
println (RaceRegistration.get(r.toLong())).compositeEvent
The following error is thrown. As you can see the first print succeeds i.e it gets the Registration domain but the second println fails. My question is why is it throwing null pointer when we are certain that the RaceRegistration domain was accessed successfully.
com.runnercard.registration.RaceRegistration : 8
ERROR errors.GrailsExceptionResolver: NullPointerException occurred when processing request: [POST] /roadrace/message/sendEmail - parameters:
I appreciate any help. Thanks!
Null is null. Don't doubt this: it is true.
The 'void' println expression evaluates to null and the failing code is roughly equivalent to the following:
x = println (RaceRegistration.get(r.toLong()))
// x is null - so the following results in a NullPointerException
x.compositeEvent
It is probable that the parenthesis is merely in the wrong spot (or even over-specified):
println (RaceRegistration.get(r.toLong()).compositeEvent)
// -or
println RaceRegistration.get(r.toLong()).compositeEvent
I've noticed some strange behaviour when resolving Grails messages using the g.message tag. In my properties file I've defined this message:
deleted={0} has been deleted
If I resolve this with:
Long id = 1878L
message(code: 'festival.deleted', args: [id.toString()])
the result is:
1878 has been deleted
which is what I would have expected. However, if I resolve it with:
Long id = 1878L
message(code: 'festival.deleted', args: [id])
the result is:
1,878 has been deleted
It's not clear to me why the number is formatted as "1,878" before it's substituted into the message. I thought perhaps toString() is called on all message arguments if they're not already of type String, but this doesn't appear to explain this behaviour, because
id.toString() == "1878"
The g.message tag uses Java's MessageFormat to generate the text output. MessageFormat has several default ways of formatting arguments if no argument format is specified. {0} has been deleted says there's an argument but doesn't say how to format it.
If the argument is a String, the string is inserted into the message. If the argument is a Number, NumberFormat is used.
groovy:000> NumberFormat.getInstance().format(1878L)
===> 1,878
There's a nice table in the docs for format() that breaks down what happens in what cases. If you want to use a Long as your argument without calling toString() on it, you can change your argument to {0,number,#} which would be equivalent to
groovy:000> new DecimalFormat("#", DecimalFormatSymbols.getInstance()).format(1878L)
===> 1878