Flow's docs say: When you create an object without any properties, you create an unsealed object type in Flow. Is it possible to create a sealed object without properties?
My use case is as follows. I want to initialize state to an empty object, and give state the following type:
type EmployeesViewState = {|
employeesRequest?: Request<Array<Employee>>,
geosRequest?: Request<Array<Geo>>,
|};
The error I get when I try to assign an empty object is
33: state: EmployeesViewState = {};
^^ object literal. Inexact type is incompatible with exact type
33: state: EmployeesViewState = {};
^^^^^^^^^^^^^^^^^^ exact type: object type
Of course, since I don't have the requests available yet, I cannot assign them. I also can't assign undefined to the object because the state is defined with pipes, i.e. it is an exact type.
I can trick flow by saying const a: any = {}; state = a; but that seems really hacky. Any other ways of tackling this issue?
This is certainly one of Flow's warts. However, it has a fairly simple workaround. Just pass your object through Object.freeze:
Object.freeze({})
Of course this only works if you weren't going to mutate it, but I find that in cases like this I rarely want to anyway.
Related
val args = Bundle()
args.putString("type", details.type)
navigator.navigate(context!!, findNavController(), Destination.TYPE, args)
I am quite confused as to why in the receiving fragment when I go to access the arguments I have passed through it is responding with...
val type: String = arguments.getString("type")
The arguments.getString is all underlined red and says "Required String Found String?" But how when I called method "putString"?!?
It is resulting in text not being rendered in the new fragment and I assume this is a nullability issue.
It's a matter of knowledge that is available in the receiving Fragment.
The Fragment is not aware of how its arguments were created (or modified) so it has to assume the "type" key you're looking for might not be in the arguments Bundle. That's why it returns a nullable (String?) result (the null value would mean absent in arguments).
Your fragment might be created in many places in your app and its arguments might have been modified in many places. We have no way of tracking that.
There are different solutions for this problem, depending on your approach in other parts of the code and how "confident" you are in creating of your Fragment.
I would usually choose a solution in which I assume setting the type is mandatory. Therefore if the type is absent - I fail fast. That would mean the Fragment was misused.
val type: String = arguments!!.getString("type")!!
The code above will crash if either:
a) arguments weren't set, or
b) String with type wasn't put in the arguments Bundle.
You are right, that is a : null ability issue.
First you should be sure if you are expecting a value, so try adding "?" or "!!", i would recommend "?", or go with the block of if {} else
To read the string safely you can use:
val type: String = arguments?.getString("type").orEmpty()
The orEmpty call at the end ensures that a valid String is returned even if either arguments or getString() returns null.
The method signature for getString() returns a nullable String. This is because at compile time, the compiler can't know if the value exists in the bundle or not. You will have the same issue when retrieving anything from any Map.
If you know for certain that the value in the bundle or map should exist at the time you call getString(), you can use the !! operator. That's what it's there for. When you know something should always be there, it is appropriate to want an exception to be thrown (in this case KNPE) if it's not there so you can easily find any programming error during testing.
isEmpty() or ?.let aren't helpful in this particular case because they would just be masking a programming error and making it harder to discover or debug.
Hey guys this code is part of a mock client, mock server interaction. I am having trouble understanding context.
Here I explicitly "associate" my tracker interface with context using 'WithValue' and then inject it into my request using WithContext. But when I check if my request's context contains the tracker interface I am returned the error "This context should contain a tracker" . What is it about context and WithValue that I am just not understanding?
var tracker Tracker
ctx := context.WithValue(context.Background(), contextKey, tracker)
req := httptest.NewRequest("GET", "localhost:12345/test", nil)
req.Header.Add(HEADER)
req = req.WithContext(ctx)
_, ok := ctx.Value(contextKey).(Tracker)
if !ok {
log.Fatal("1: This context should contain a tracker")
}
Tracker is an interface, and it's not set to anything, so it's nil. So, it can't change nil to a Tracker, so it fails.
https://play.golang.org/p/4-KQXlCR8vD
The problem isn't that tracker is nil, the problem is that it doesn't contain a value of a concrete type that implements Tracker. The value of tracker could be nil, and this would work, but it has to be a "typed" nil.
The type assertion fails, because type assertions and type switches only work when the instance being asserted has a concrete type. A value can be of a concrete type by declaration , assignment, type assertion , or a type switch case.
When you do the type assertion ctx.Value(contextKey).(Tracker)
There's (conceptually) a 2-step process to this:
Determine the ctx.Value(contextKey)'s concrete type.
Determine whether that concrete type implements Tracker.
Here's a playground example that hopefully illustrates this better: https://play.golang.org/p/ojYzLObkisd
The DoAny() function in there is emulating what is happening when you put your tracker into context and then try to retrieve it with the type assertion.
I know this is just a basic example, but it's not very good practice to use var something SomeInterfaceType, even if you do assign it a value. You should use concrete types for that. Or even better, just use type inference, and you won't have to worry about it. For example:
type Foo interface {
DoFoo() string
}
type MyFoo struct {}
func (f *MyFoo) DoFoo() string {
return "some foo value"
}
// not so good
var f Foo = new(MyFoo)
// good
var f *MyFoo = new(MyFoo)
// better
f := new(MyFoo)
This leverages the fact that interfaces are implicit in Go, and leads to much more obvious and maintainable code, especially in larger projects. Declaring a variable with an interface type is essentially making your variable poloymorphic, but the real power of interfaces isn't polymorphism. The real power is in using them as "functional requirements" for your package's exposed functions/methods. One rule that illustrates this really well is "Accept interfaces, return structs".
EDIT:
I've edited my original answer to correct some mistakes and make some improvements. I also would like to answer a follow-up question from the OP:
what I did not understand is that unless you have an object that utilizes that tracker's methods your interface is nil. Is this correct thinking?
I think what you're trying to say is correct, but the words used aren't quite right. First, there are no objects in Go, as it is not object-oriented. Where in OOP languages, objects hold instances of types, Go uses variables and constants to hold instances of types. So the concept exists, but not by the same name. So your tracker variable will be an instance of a type that satisfies your Tracker interface, but its value with be nil unless you assign it a non-nil instance of a type that satisfies the Tracker interface.
I'm experimenting with the reflection functionality in Kotlin, but I can't seem to understand how to obtain a KType value.
Suppose I have a class that maps phrases to object factories. In case of ambiguity, the user can supply a type parameter that narrows the search to only factories that return that type of object (or some sub-type).
fun mapToFactory(phrase: Phrase,
type: KType = Any::class): Any {...}
type needs to accept just about anything, including Int, which from my experience seems to be treated somewhat specially. By default, it should be something like Any, which means "do not exclude any factories".
How do I assign a default value (or any value) to type?
From your description, sounds like your function should take a KClass parameter, not a KType, and check the incoming objects with isSubclass, not isSubtype.
Types (represented by KType in kotlin-reflect) usually come from signatures of declarations in your code; they denote a broad set of values which functions take as parameters or return. A type consists of the class, generic arguments to that class, and nullability. The problem with types at runtime on JVM is that because of erasure, it's impossible to determine the exact type of a variable of a generic class. For example if you have a list, you cannot determine the generic type of that list at runtime, i.e. you cannot differentiate between List<String> and List<Throwable>.
To answer your initial question though, you can create a KType out of a KClass with createType():
val type: KType = Any::class.createType()
Note that if the class is generic, you need to pass type projections of generic arguments. In simple cases (all type variables can be replaced with star projections), starProjectedType will also work. For more info on createType and starProjectedType, see this answer.
Since Kotlin 1.3.40, you can use the experimental function typeOf<T>() to obtain the KType of any type:
val int: KType = typeOf<Int>()
In contrast to T::class.createType(), this supports nested generic arguments:
val listOfString: KType = typeOf<List<String>>()
The typeOf<T>() function is particularly useful when you want to obtain a KType from a reified type parameter:
inline fun <reified T> printType() {
val type = typeOf<T>()
println(type.toString())
}
Example usage:
fun main(args: Array<String>) {
printType<Map<Int, String>>()
// prints: kotlin.collections.Map<kotlin.Int, kotlin.String>
}
Since this feature is still in experimental status, you need to opt-in with #UseExperimental(ExperimentalStdlibApi::class) around your function that uses typeOf<T>(). As the feature becomes more stable (possibly in Kotlin 1.4), this can be omitted. Also, at this time it is only available for Kotlin/JVM, not Kotlin/Native or Kotlin/JS.
See also:
Release announcement
API Doc (very sparse currently)
NOTE: I am not asking about difference between pointer and reference, and for this question it is completely irrelevant.
One thing I couldn't find explicitly stated -- what model does Nim use?
Like C++ -- where you have values and with new you create pointers to data (in such case the variable could hold pointer to a pointer to a pointer to... to data)?
Or like C# -- where you have POD types as values, but user defined objects with referenced (implicitly)?
I spotted only dereferencing is automatic, like in Go.
Rephrase. You define your new type, let's say Student (with name, university, address). You write:
var student ...?
to make student hold actual data (of Student type/class)
to make student hold a pointer to the data
to make student hold a pointer to a pointer to the data
Or some from those points are impossible?
By default the model is of passing data by value. When you create a var of a specific type, the compiler will allocate on the stack the required space for the variable. Which is expected, as Nim compiles to C, and complex types are just structures. But like in C or C++, you can have pointers too. There is the ptr keyword to get an unsafe pointer, mostly for interfacing to C code, and there is a ref to get a garbage collected safe reference (both documented in the References and pointer types section of the Nim manual).
However, note that even when you specify a proc to pass a variable by value, the compiler is free to decide to pass it internally by reference if it considers it can speed execution and is safe at the same time. In practice the only time I've used references is when I was exporting Nim types to C and had to make sure both C and Nim pointed to the same memory. Remember that you can always check the generated C code in the nimcache directory. You will see then that a var parameter in a proc is just a pointer to its C structure.
Here is an example of a type with constructors to be created on the stack and passed in by value, and the corresponding pointer like version:
type
Person = object
age: int
name: string
proc initPerson(age: int, name: string): Person =
result.age = age
result.name = name
proc newPerson(age: int, name: string): ref Person =
new(result)
result.age = age
result.name = name
when isMainModule:
var
a = initPerson(3, "foo")
b = newPerson(4, "bar")
echo a.name & " " & $a.age
echo b.name & " " & $b.age
As you can see the code is essentially the same, but there are some differences:
The typical way to differentiate initialisation is to use init for value types, and new for reference types. Also, note that Nim's own standard library mistakes this convention, since some of the code predates it (eg. newStringOfCap does not return a reference to a string type).
Depending on what your constructors actually do, the ref version allows you to return a nil value, which you can treat as an error, while the value constructor forces you to raise an exception or change the constructor to use the var form mentioned below so you can return a bool indicating success. Failure tends to be treated in different ways.
In C-like languages theres is an explicit syntax to access either the memory value of a pointer or the memory value pointed by it (dereferencing). In Nim there is as well, and it is the empty subscript notation ([]). However, the compiler will attempt to automatically put those to avoid cluttering the code. Hence, the example doesn't use them. To prove this you can change the code to read:
echo b[].name & " " & $b[].age
Which will work and compile as expected. But the following change will yield a compiler error because you can't dereference a non reference type:
echo a[].name & " " & $a[].age
The current trend in the Nim community is to get rid of single letter prefixes to differentiate value vs reference types. In the old convention you would have a TPerson and an alias for the reference value as PPerson = ref TPerson. You can find a lot of code still using this convention.
Depending on what exactly your object and constructor need to do, instead of having a initPerson returning the value you could also have a init(x: var Person, ...). But the use of the implicit result variable allows the compiler to optimise this, so it is much more a taste preference or requirements of passing a bool to the caller.
It can be either.
type Student = object ...
is roughly equivalent to
typedef struct { ... } Student;
in C, while
type Student = ref object ...
or
type Student = ptr object ...
is roughly equivalent to
typedef struct { ... } *Student;
in C (with ref denoting a reference that is traced by the garbage collector, while ptr is not traced).
I find that in my daily Flex/Flash work, I do this number a lot:
//Calling a function...
MyCustomObject(container.getChildAt(i)).mySpecialFunction();
The question is - is this the best way to do this? Should I do this:
//Calling a function
var tempItem:MyCustomObject = container.getChildAt(i) as MyCustomObject;
tempItem.mySpecialFunction();
It might be incidental but I'm just wondering if there is an "accepted" way or a preferred way to do this. The second option seems more readable but I wonder if it takes more of a performance hit to create a new variable. Or does it all come down to style and preference?
It's important to remember that there is a difference between explicit casting and using the as keyword. Casting throws an error when it fails, whereas the as keyword does not (it just returns null).
// a casting error
try {
var number:int = 666;
var urlreq:URLRequest = URLRequest( number );
} catch(e:TypeError) {
// TypeError: Error #1034: Type Coercion failed: cannot
// convert 666 to flash.net.URLRequest.
trace(e);
}
Whereas the as keyword fails silently:
var number:int = 666;
var urlreq:URLRequest = number as URLRequest;
trace(urlreq); // prints null to the debug pane
Personally, I bear these behaviours in mind when deciding method to use. Generally, I'd recommend casting explicitly, as you'll know exactly how/when a cast failed. Often, though, you might want to fail silently and continue.
It generally doesn't matter. Creating a var just creates a pointer to the object, so it's not using more memory or anything like that.
The second example is definitely more readable and debuggable and should thus be preferred.
The risk you run from creating temp vars is that you might delay or prevent garbage collection for that object. This generally isn't a problem when it's just a local var in a function; just keep scope in mind when you're creating vars and passing them around.
For in-depth on the subject, read Grant Skinner's series on resource management in AVM2:
http://www.gskinner.com/blog/archives/2006/06/as3_resource_ma.html
for the second example you might want to test for the nullity to avoid a NullPointerException when invoking "mySpecialFunction", e.g.
var tempItem:MyCustomObject = container.getChildAt(i) as MyCustomObject;
if ( tempItem )
{
tempItem.mySpecialFunction();
}
I usually prefer the second approach but you have to remember that you can only use the as operator for casting "Date" and "Array" types.