Casting Protobuf Messages to their Extended type - swift

Im learning about protobuf and am playing with alexeyxo/protobuf-swift.
Is there a way to cast protobuf Messages into the type they extend?
proto file:
message Command_Login {
extend SessionCommand {
optional Command_Login ext = 1001;
}
optional string user_name = 1;
optional string password = 2;
}
Here is the swiftcode:
let commandContainerBuilder = CommandContainer.Builder()
commandContainerBuilder.sessionCommand.append(commandLogin)
// sessionCommand is an array of SessionCommand (of which Command_Login extends)
Error:
Cannot convert value of type CommandLogin? to expected argument type SessionCommand

Sorry, you've misinterpreted extensions. I say "sorry" because this is probably my fault -- I designed the "extensions" feature, and unfortunately by using the word "extend" I confused a lot of people.
You see, extensions have nothing to do with inheritance. In your example, you are not declaring that Command_Login is any kind of subclass of SessionCommand. This is easier to understand if we shift the declarations around a bit:
message Command_Login {
optional string user_name = 1;
optional string password = 2;
}
extend SessionCommand {
optional Command_Login ext = 1001;
}
The above is completely valid and exactly equivalent to your code except for one difference: In your version, the extension's name is Command_Login.ext (because you declared it nested inside Command_Login), but in my version the name is just ext (in the global scope). Other than namespacing, they function the same.
What the extend clause actually does is declare a new field on SessionContext, where the type of that field is Command_Login. If you happen to place an extend clause inside of a message block, this only matters for namespacing purposes, much like declaring static members of a class in C++ or Java.

Related

How to use enum in class (C++)?

enum TokenType{
Eof,
Ws,
Unknow,
//lookahead 1 char
If,Else,
Id,
Int,
//lookahead 2 chars
Eq,Ne,Lt,Le,Gt,Ge,
//lookahead k chars
Real,
Sci
};
class Token{
private:
TokenType token;
string text;
public:
Token(TokenType token,string text):token(token),text(text){};
static Token eof(Eof,"Eof");
};
In this code I want to create a Token Object eof, but when I compile it it tells me that the Eof is not a Type. Why?
When I use TokenType token=TokenType::Eof it works. But when I passed the Eof into the constructor as a parameter, an error occurred. How could I solve it? Is it related to the scope. I try to use TokenType::Eof as the parameter also fail.
The problem is unrelated to the enumeration, the problem is that the compiler thinks you're declaring a function. For inline initialization use either curly braces {} or assignment-like syntax.
However, you can't define instances of a class inside the class itself, because the class isn't actually fully defined yet. It will also leas to a kind of infinite recursion (Token contains a Token object, which contains a Token object, which contains a Token object, ... and so on in infinity).
You can, on the other hand, define pointers to class inside itself, or references, because that doesn't require a fully defined class, only knowledge that the class exists.
So as a workaround perhaps use reference, that you initialize to a variable defined outside the class:
class Token
{
// ...
private:
static Token& eof; // Declare the reference variable
};
And in a source file:
namespace
{
// Define the actual "real" instance of the eof object
Token eof{ Eof, "Eof" };
}
// Define the reference and initialize it
Token& Token::eof = eof;
Look closely. The error messages tells you where exactly your error lies, including a line number. The compiler sees a function prototype, with Eof being the type of the first argument.
Because Eof is not a type, but just one possible value of a type.
It's really not clear what your design intent here is, but you need to make a clear mental difference between the type you've created, TokenType and its different values.

Multi if statement in class parameters setting

I know that in the latest version of dart we can use if else statements inside the build method. Does anyone know if we can use also if else statement when we setting class parameters? I know I can do inline statement there but inline is a bit hard to read when there are multiple conditions
const int i = 0;
class Person {
// NewClass n = NewClass(a: i == 0 ? 'a' : 'b'); //<- inline statement working
NewClass n = NewClass(a: if(i == 0) 'a' else 'b'); //<- if statement doesn't
}
class NewClass {
final String a;
const NewClass({this.a});
}
Edit:
Basically in my case I've got an TextField widget where I set its's type parameter from enum (Type.text, Type.numeric...) According to this parameter I want to set The textField parameters (textCapitalization, maxLength and so on)
As per your comment, you are already creating an enum for specifying the type of the fields.
enum Type {text, numeric}
Now for specifying the properties of that particular type, you can add an extension on this enum, as shown below:
extension TextFieldProperties on Type {
int get maxLength {
if (this == Type.text) {
return 10;
}
return 12;
}
}
So in your field class you already have a type defined, you can use that type variable to get the properties of that particular type of field.
Type type = Type.text;
print(type.maxLength); // Will print 10
type = Type.numeric;
print(type.maxLength); // Will print 12
Note: It will work only in Dart 2.7 and above
You want the conditional expression (?:), not the conditional statement or literal entry (if), as you have already discovered.
The reason if doesn't work is that if only works as a statement or as a collection literal entry. It doesn't work in arbitrary expressions.
The reason for the distinction is that the if syntax allows you to omit the else branch. That only makes sense in places where "nothing" is a valid alternative. For a statement, "doing nothing" is fine. For a collection, "adding nothing" is also fine.
In an expression context, you must evaluate to a value or throw. There is no reasonable default that we can use instead of "nothing", so an if is not allowed instead of an expression.
Doesn't work because this syntax doesn't exist in Dart. The only way to do what you would like to do is to use the ternary operator.
If you try it in the DartPad you will get an error.
I suggest you to use a function to return the right value.

Problems with Dateish strings

This code (for checking the changed timestamp of the current directory):
my $date = ".".IO.changed.DateTime.yyyy-mm-dd but Dateish;
say $date;
yields the error:
«Ambiguous call to 'gist(Str+{Dateish}: )'; these signatures all match:␤: (Str:D: *%_)␤:(Dateish:D: │ avalenn
| *%_)␤ in block <unit> at <tmp> line 1␤␤»
Without the Dateish mix in, the string is simply 2018-05-12. Using any other kind of Dateish function, like .week-year also yields a different error:
«Str+{Dateish}␤Invocant of method 'Bridge' must be an object instance of type 'Int', not a type │ a3r0
| object of type 'Int'. Did you forget a '.new'?␤ in block <unit> at <tmp> line 1␤␤»
Does it simply mean that you can't mix in a string with Dateish? I've done something similar with hours without a problem.
To answer your question, we should look at that role:
my role Dateish {
has Int $.year;
has Int $.month; # should be int
has Int $.day; # should be int
has Int $.daycount;
has &.formatter;
...
multi method Str(Dateish:D:) {
&!formatter ?? &!formatter(self) !! self!formatter
}
multi method gist(Dateish:D:) { self.Str }
...
}
So, role Dateish has several attributes, and the methods use those attributes to calculate their return values.
When you do $some-string but Dateish, you are not doing anything to initialize the attributes, and thus method calls that use them (potentially indirectly) fail in interesting ways.
How do you get a Dateish object from a DateTime then? Well, DateTime is one, already, or you can coerce to Date if that is what you want:
my $date = ".".IO.changed.DateTime.Date; say $date
You might also try to instantiate a Dateish by supplying all attributes, but I don't see any advantage over just using Date as intended.

How do I cast to an interface an object may implement?

I have the following classes & interfaces:
export interface IBody {
body : ListBody;
}
export class Element {
// ...
}
export class Paragraph extends Element implements IBody {
// ...
}
export class Character extends Element {
// ...
}
I have code where I will get an array of Element derived objects (there are more than just Paragraph & Character). In the case of those that implement IBody, I need to take action on the elements in the body.
What is the best way to see if it implements IBody? Is it "if (element.body !== undefined)"?
And then how do I access it? "var bodyElement = <IBody> element;" gives me an error.
C:/src/jenova/Dev/Merge/AutoTagWeb/client/layout/document/elements/factory.ts(34,27): error TS2012: Cannot convert 'Element' to 'IBody':
Type 'Element' is missing property 'body' from type 'IBody'.
Type 'IBody' is missing property 'type' from type 'Element'.
thanks - dave
An interface in TypeScript is a compile-time only construct, with no run-time representation. You might find section 7 of the TypeScript specification interesting to read as it has the complete details.
So, you can't "test" for an interface specifically. Done correctly and completely, you generally shouldn't need to test for it as the compiler should have caught the cases where an object didn't implement the necessary interface. If you were to try using a type assertion:
// // where e has been typed as any, not an Element
var body = <IBody> e;
The compiler will allow it without warning as you've asserted that the type is an IBody. If however, e were an Element in scope, the compiler as you've shown will check the signature of the Element and confirm that it has the properties/methods declared by IBody. It's important to note that it's checking the signature -- it doesn't matter that it may not implement IBody as long as the signature matches up.
Assuming that Element has a signature that matches IBody, it will work. If it does not, you'll get the compiler error you're receiving. But, again, if it's declared as any, the assertion will pass and at run-time, unless the type has the methods defined on IBody, the script will fail.
As your Element is the base class, you cannot check for IBody. You could declare an argument as any:
function someFeature(e: any) {
}
And then assert that the IBody is present:
function someFeature(e: any) {
var body :IBody = <IBody> e;
// do something
}
However, if you do need a run-time check, you'd need to look for the function on the prototype or as a property before using it. While that could be misleading in some cases, the interface in TypeScript also may not have caught the mismatch either. Here's an example of how you could check for the existence of a specific function.
It might look like this:
function someFeature(e: any) {
var body = <IBody> e;
if (typeof (body.someFunctionOnBodyInterface) === "undefined") {
// not safe to use the function
throw new Error("Yikes!");
}
body.someFunctionOnBodyInterface();
}

- (double) a valid return type for a method in Objective C

I'm trying to return a double from another object then store that into a new double but i'm getting the error incompatible types in initialization. What am I missing here?
double gradePoints = 0.0;
double other = [aCourse getGradePoints];
gradePoints = gradePoints + other;
This is in my other object
- (double) getGradePoints{
return 12.0;
}
Most likely you have forgotten to add the getGradePoints method to an interface declaration: This will result in the method being implicitly declared as -(id)getGradePoints; resulting in the warning you are seeing.
Is the reference to aCourse typed or is it an id? If I remember correctly, if the class of aCourse isn't known to the compiler, it assumes that the result of all method calls is type id.
The getter/setter kvo standard defines getters in the form of getPropertyName. If you have a property called gradePoints the compiler will interpret getGradePoints as the getter for that property and if the property is not defined as a double, it will complain.
Even defining a local variable like this:
double gradePoints = 0.0;
double other = [aCourse getGradePoints];
... may confuse the compiler because it may try to process getGradePoints as the getter for gradePoints.
Objective-C relies on naming conventions to find specific types of methods because it can't assume at compile time what methods an object in a particular circumstance will have.
In general you should avoid using method names that begin with "get" and "set" because the compiler wants to treat them as getter and setter methods for properties. The potential for compiler confusion is high.
I try to use prefixes like "fetch", "grab", "obtain" etc instead of "get" just to be safe.