A haxe function has some parameters whose default values I'd like to use, so I don't need to import anything (they're basic types underneath). If they were last in the parameter order, I could get away with just not including them. But they're first, before some defaults I do want to override.
I'm not allowed to null them on native. _ doesn't compile (I don't think it's meant for this context.) Am I forced to import and copy the defaults in verbatim, or is there another way?
I tried .bind(_, ...)() but that gives Usage of _ is not supported for optional non-nullable arguments.
That error comes from the argument having a non-nullable type (Int, Float or Bool on a static target). If this function is part of your code and not some library, you could just make it nullable with Null<T> or ?.
As long as the arguments are nullable, Haxe also allows you to simply skip them if they are distuingishable (i.e. the type of the value passed must be different from the one(s) you want to skip). This means you don't have to use bind() or explicitly pass null. See the fourth example on the manual's Optional Arguments page.
If making the arguments nullable isn't an option for you in this particular case, you're probably going to have to copy the defaults (although I'm sure it's possible to come up with a clever macro solution for this).
Related
Is there a neat solution to raise an error if a value is passed to the NamedTuple field that does not match the declared type?
In this example, I intentionally passed page_count str instead of int. And the script will work on passing the erroneous value forward.
(I understand that linter will draw your attention to the error, but I encountered this in a case where NamedTuple fields were filled in by a function getting values from config file).
I could check the type of each value with a condition, but it doesn't look really clean. Any ideas? Thanks.
from typing import NamedTuple
class ParserParams(NamedTuple):
api_url: str
page_count: int
timeout: float
parser_params = ParserParams(
api_url='some_url',
page_count='3',
timeout=10.0,
)
By design, Python is a dynamically typed language which means any value can be assigned to any variable. Typing is only supported as hints - the errors might be highlighted in your IDE, but they do not enforce anything.
This means that if you need type checking you have to implement it yourself. On the upside, this can probably be automated, i.e. implemented only once instead of separately for every field. However, NamedTuple does not provide such checking out of the box.
I've been using Python's type annotations in an unusual way: I have some code that inspects the annotations of a function's arguments at run-time, searches for values that match the types of the arguments, and calls the function with values of appropriate types (if found).
This has been working wonderfully, and was remarkably easy to implement, but the source file has grown fairly large, so today I tried breaking it into multiple files. I found that get_type_hints() can't evaluate a type annotation if it's from a module other than the current one, at least not without being given a global namespace where all the needed types are defined.
I'm using from __future__ import annotations everywhere, so the type annotations in each function's .__annotations__ attribute are stored as strings in need of evaluation. To evaluate them, I need the globals from the module where the function was defined. How can I get that? Or will that even work? I'm using if TYPE_CHECKING: to avoid circular imports; consequently some annotations won't be available at run-time in each module where they're applied to a function.
Here's the code that extracts the types of the function arguments, if that helps:
def params_of(func: Callable) -> Iterable[Tuple[str, TypeAnnotation]]:
type_hints = get_type_hints(func)
for param_name in inspect.signature(func).parameters:
if param_name == 'return':
continue # disregard return type
yield (param_name, type_hints.get(param_name, Any))
(TypeAnnotation is only for readability; it's defined to Any.)
Let's say I'm using gdscript static typing and for one function parameter I don't know in advance what I'm going to get. That's what typing.Any is for in python. How do I do it with gdscript?
It seems that Variant is not a valid type and I'm not sure about using Object for that purpose (since it could be a built-in)
edit
Leaving the type blank obviously works, but the docs has a specific section called typed-or-dynamic-stick-to-one-style, and since we're already kinda short on good practices using gdscript I'd rather find another way
Any idea?
As of Godot 3.2, GDScript does not feature a Variant or any type hint yet. However, you can still use the Object type hint if you expect a variable to hold any object (or null, as Object is nullable by design). Object may not hold primitive types like int or bool though.
Therefore, you should just leave out the type hint for now.
I'm writing a class named "MyObject".
one of the class methods is:
addTo: aCodeString assertType: aTypeCollection
when the method is called with aCodeString, I want to add (in runtime) a new method to "MyObject" class which aCodeString is it's source code and inject type checking code into the source code.
for example, if I call addTo: assertType: like that:
a := MyObject new.
a addTo: 'foo: a boo:b baz: c
^(a*b+c)'
assertType: #(SmallInteger SmallInteger SmallInteger).
I expect that I could write later:
answer := (a foo: 2 boo: 5 baz: 10).
and get 20 in answer.
and if I write:
a foo: 'someString' boo: 5 baz: 10.
I get the proper message because 'someString' is not a SmallInteger.
I know how to write the type checking code, and I know that to add the method to the class in runtime I can use 'compile' method from Behavior class.
the problem is that I want to add the type checking code inside the source code.
I'm not really familiar with all of squeak classes so I'm not sure if I rather edit the aCodeString as a string inside addTo: assertType: and then use compile: (and I don't know how to do so), or that there is a way to inject code to an existing method in Behavior class or other squeak class.
so basically, what I'm asking is how can I inject string into an existing string or to inject code into an existing method.
There are many ways you could achieve such type checking...
The one you propose is to modify the source code (a String) so as to insert additional pre-condition type checks.
The key point with this approach is that you will have to insert the type checking at the right place. That means somehow parsing the original source (or at least the selector and arguments) so as to find its exact span (and the argument names).
See method initPattern:return: in Parser and its senders. You will find quite low level (not most beautiful) code that feed the block (passed thru return: keyword) with sap an Array of 3 objects: the method selector, the method arguments and the method precedence (a code telling if the method is connected to unary, binary or keyword message). From there, you'll get enough material for achieving source code manipulation (insert a string into another with copyReplace:from:to:with:).
Do not hesitate to write small snippets of code and execute in the Debugger (select code to debug, then use debug it menu or ALT+Shift+D). Also use the inspectors extensively to gain more insight on how things work!
Another solution is to parse the whole Abstract Syntax Tree (AST) of the source code, and manipulate that AST to insert the type checks. Normally, the Parser builds the AST, so observe how it works. From the modified AST, you can then generate new CompiledMethod (the bytecode instructions) and install it in methodDictionary - see the source code of compile: and follow the message sent until you discover generateMethodFromNode:trailer:. This is a bit more involved, and has a bad side effect that the source code is now not in phase with generated code, which might become a problem once you want to debug the method (fortunately, Squeak can used decompiled code in place of source code!).
Last, you can also arrange to have an alternate compiler and parser for some of your classes (see compilerClass and/or parserClass). The alternate TypeHintParser would accept modified syntax with the type hints in source code (once upon a time, it was implemented with type hints following the args inside angle brackets foo: x <Integer> bar: y <Number>). And the alternate TypeHintCompiler would arrange to compile preconditions automatically given those type hints. Since you will then be very advanced in Squeak, you will also create special mapping between source code index and bytecodes so as to have sane debugger and even special Decompiler class that could recognize the precondition type checks and transform them back to type hints just in case.
My advice would be to start with the first approach that you are proposing.
EDIT
I forgot to say, there is yet another way, but it is currently available in Pharo rather than Squeak: Pharo compiler (named OpalCompiler) does reify the bytecode instructions as objects (class names beginning with IR) in the generation phase. So it is also possible to directly manipulate the bytecode instructions by proper hacking at this stage... I'm pretty sure that we can find examples of usage. Probably the most advanced technic.
Recently I am dealing with escaping/encoding issues. I have a bunch of APIs that receive and return Strings encoded/escaped differently. In order to clean up the mess I'd like to introduce new types XmlEscapedString, HtmlEscapedString, UrlEncodedString, etc. and use them instead of Strings.
The problem is that the compiler cannot check the encoding/escaping and I'll have runtime errors.
I can also provide "conversion" functions that escape/encode input as necessary. Does it make sense ?
The compiler can enforce that you pass the types through your encoding/decoding functions; this should be enough, provided you get things right at the boundaries (if you have a correctly encoded XmlEscapedString and convert it to a UrlEncodedString, the result is always going to be correctly encoded, no?). You could use constructors or conversion methods that check the escaping initially, though you might pay a performance penalty for doing so.
(Theoretically it might be possible to check a string's escaping at compile time using type-level programming, but this would be exceedingly difficult and only work on literals anyway, when it sounds like the problem is Strings coming in from other APIs).
My own compromise position would probably be to use tagged types (using Scalaz tags) and have the conversion from untagged String to tagged string perform the checking, i.e.:
import scalaz._, Scalaz._
sealed trait XmlEscaped
def xmlEscape(rawString: String): String ## XmlEscaped = {
//perform escaping, guaranteed to return a correctly-escaped String
Tag[String, XmlEscaped](escapedString)
}
def castToXmlEscaped(escapedStringFromJavaApi: String) = {
require(...) //confirm that string is properly escaped
Tag[String, XmlEscaped](escapedStringFromJavaApi)
}
def someMethodThatRequiresAnEscapedString(string: String ## XmlEscaped)
Then we use castToXmlEscaped for Strings that are already supposed to be XML-escaped, so we check there, but we only have to check once; the rest of the time we pass it around as a String ## XmlEscaped, and the compiler will enforce that we never pass a non-escaped string to a method that expects one.