Using UILocalizedIndexedCollation.section(for: collationStringSelector:) with array of structs - arrays

Assume I have an array of structs like so:
struct Record {
let name: String
}
let array = [Record(name: "John"), Record(name: "Jim"), Record(name: "Bob")]
I would like to get the index of each element using UILocalizedIndexedCollation.section(for: collationStringSelector:). The problem is, when I pass:
#selector(getter: record.name)
the following error is returned:
Argument of '#selector' refers to var 'name' that is not exposed to
Objective-C
Is there any way of exposing an instance value in a struct to a #selector? (NB: the struct I am passing is used extensively throughout my app and I don't really want to change it to a class)

Converting the struct variable to an NSString and using one of NSString's methods / variables is a work around that fixed the issue:
let index = UILocalizedIndexedCollation.current().section(for: (record.name as NSString), collationStringSelector: #selector(getter: NSString.uppercased))

Related

Can I use strings within an array to name struct variables using concatenation, macros, or similar?

I have an array of animal names in the order that I intend to create each struct 'animal' and store it in farm_animals, a struct of animals.
typedef struct ani animal;
animal* farm_animals[128] = {0};
Although the below code is totally invalid, I have included it here to show exactly what I have thought of achieving in practice. I want to declare a variable of type animal corresponding to a string literal in the array, and then somehow use that literal as the name of the animal and store it in an array.
char* animal_names [] = {"Oliver", "Marcus", "Mike", "John", "Tom", "Daisy", "Lilac", "Rose", "Jim"};
for (int i = 0; i < 9; i++) {
animal animal_names[i];
farm_animals[i] = animal_names[i];
}
I have researched and found many other similar posts which conclude that since C is a compiled not interpreted language, it is not possible to name a variable with the value of a string. However, I was wondering if it is possible to concatenate the string name with a suffix (like the index number) to create an entirely new 'string name' to refer to the animal. I have also though of a macro using an array or the same animal_names array, but this has not been clear for me to implement as a beginner.
I think this sort of idea in C is far-fetched, but I really wonder if there is a way to name these structs using a for loop and array of names, rather than manually creating 100+ structs.
Yes, it is not possible to dynamically name variables in C. If I understand correctly, you want to create an animal type corresponding to a string and then name it that name.
The advantage with using structs is that you can combine related/relevant data into a single variable (the struct) – which itself is a collection of multiple variables.
I would suggest organizing something like this:
typedef struct animal {
char[20] name;
char[20] type;
} animal;
You can replace the character array with a pointer to the string (char*) as well. Also, if you know the type of animals that could be created you can instead create an enum like this:
#define MAX_NAME_LEN 20
#define MAX_NUM_ANIMALS 10
enum animalType {
LION,
ELEPHANT,
FALCON,
PARROT
};
typedef struct animal {
char[MAX_NAME_LEN] name;
enum animalType type;
} animal;
int main(void) {
animal listOfAnimals[MAX_NUM_ANIMALS];
listOfAnimals[0].type = PARROT;
listOfAnimals[0].name = "my parrot";
return 0;
}
So, instead of making 100+ structs, you would make an array of structs and store the type of animal as a data member. Then you could use some mapping mechanism or conditional logic to assign these types to the struct variables as per your needs.

Unable to append string to mutable array in Swift

Context - I'm currently learning Swift Struct. So I decided to create my own Phone structure in Playground. (see below)
Problem -
The downloadApp method on the phone struct is throwing the following error.. Cannot use mutating member on immutable value: 'self' is immutable.
Expect outcome - To peacefully append new strings to my apps property, which is an array of strings.
Swift code
struct Phone {
let capacity : Int
let Brand : Sting
var name: String
let model: String
var apps: [String]
var contacts: [String]
var formatCapacity: String {
return "\(capacity)GB"
}
func downloadApp(name: String){
apps.append(name) // ERROR
}
}
You simply need to mark downloadApp as mutating. The issue is caused by the fact that downloadApp is declared in a struct type, which is a value type and hence if you mutate any properties (namely, the apps array here) of the struct, you actually mutate the struct itself. By marking the function as mutating, the compiler allows such modification of the struct through a member function of the type.
mutating func downloadApp(name: String){
apps.append(name)
}

C multilevel inheritance recursion

I have a project that must be in C (just to avoid the use C++ arguments).
The project depends on virtual tables and pointers to implement polymorphism.
Im stuck however in implementing super constructors from multi-level inheritance.
An example structure is:
Base Object
/\ /\
Constructed Object Simple Object
/\
SpecificConstructed
All objects have a name and a class.
Constructed objects may have a list of sub objects for example.
As simple object may only add a single value.
Base Object is just defined as:
struct _object {
struct _class *class;
char *name;
}
Class is where the virtual table is:
struct _class {
struct _class *super;
char *name;
size_t size;
void* (*init)(void *_this, char *name);
...
}
A constructed object is:
struct _constructed_object {
struct _object base;
void* components; //a list of sub objects for example
}
A sample simple object is:
struct _simple_object {
struct _object base;
unsigned char value; //a simple value for this specific type
}
So every object has a class, and classes can have supers, specially for the SpecificConstructed -> Constructed.
The definitions i have:
struct _class base = {0, "Base", sizeof(struct _object), base_init};
struct _class constructed = {&base, "Constructed", sizeof(struct _constructed_object}, constructed_init};
struct _class specific = {&constructed, "SpecificConstructed", sizeof(struct _constructed_object), specific_init};
struct _class simple = {&base, "SimpleOBject", sizeof(struct _simple_object}, simple_init};
This definition allows me to create objects of specify classes using a function:
new(struct _class *a_class) {
...
struct _object *o = calloc(1, a_class->size);
o->class = a_class;
o = a_class->init(o);
return o;
}
The idea is if i do:
new(SpecificConstructed)
New would create the appropriate space (sizeof(struct _constructed_object)), it would call "specific_init", which in turn would call "constructed_init" (it's super), which finally would call "base_init" (it's super). However the flow is specific_init, constructed_init, specific_init, constructed_init ...
The function i have for calling the supers initializer:
void* super_init(void* _this, char *name){
struct _object *o = (struct _object*)_this;
const struct _class *c = o->class;
const struct _class *s = c->super;
return (s && s->init) ? s->init(_this, name) : _this;
}
The simple (to - super) base method call works since i can just call the supers init.
But for the specific constructed, calling super takes me to the constructed object which is the correct step, but then instead of the constructed sending me up to the base_init, it sends me back to the specific_init call. This happens since I'm passing the same _this object which starts with the class specific i understand that, but not sure how to fix it and if its actually possible to fix?
Ive read the Object Oriented C book, but it deals with one-level inheritance Circle->Point, and the Metaclasses chapter just flew over my head. Ive also looked at the Objective-C runtime to see how that handles it, but it also has metaclasses and that i can't comprehend at the moment.
super_init can't work like that, it needs class on which to call super, otherwise (as you discovered) the immediate superclass constructor ends up calling itself over and over. Since each class knows its parent, it can call superclass's init directly. For example, simple.init will call specific.init, which will in turn call constructed.init, and so on.
If you insist on a function to do that for you, you will have to give it the class so it can (trivially) invoke the constructor of the superclass. super in Python 2 is an example of such a design. Python 3 introduces a simpler-to-use super, but it required support from the compiler to figure out the correct class to pass to the underlying function.
This is awesome stuff, I did a bit of that kind of stuff in C in the early nineties, before moving on to C++.
Unfortunately, despite the fact that your question is quite long, it is still a bit vague because it is not showing us certain things, like what is a "constructed object", (why are you calling it like that,) what is the difference between "constructed object" and "simple object", and what is "the simple->base method call". Also, why the size? Also, I think that some sample code showing the actual problem with the invocation of the constructors is necessary.
The one thing that I can tell you right now about this design is that it strikes me as odd that you are storing a pointer to the constructor in the Virtual Method Table. In all object oriented languages that I know, (C++, Java, C#) constructors are never virtual; they look a lot more like "static" methods, which in C parlance are just plain link-by-name methods. This works fine, because every class has built-in, absolutely certain, unalterable knowledge of who its base class is.
Anyhow, chained constructor invocation is supposed to happen like this:
void basemost_init( struct basemost* this, char* name )
{
this->class = &basemost_class;
this->name = name;
...
}
void intermediate_init( struct intermediate* this, char* name )
{
basemost_init( &this->base, name );
this->class = &intermediate_class;
...
}
void descendant_init( struct descendant* this, char* name )
{
intermediate_init( &this->base, name );
this->class = &descendant_class;
...
}
Edit (after some clarifications)
If you want it to look cool at the allocation end, perhaps try something like this: (I am not sure how well I remember my C syntax, so please excuse any minor inaccuracies.)
struct descendant* new_descendant( char* name )
{
struct descendant* this = malloc( sizeof struct descendant );
descendant_init( this, name );
return this;
}
This way, you don't need a size anymore. Also, note that you can pass as many constructor arguments as you want, without being restricted to a fixed, predetermined number of arguments, (which I consider to be extremely important,) and without having to use variadic constructors.
You may also be able to achieve the same thing with a #define macro for all classes, if you promise to use consistent naming, so that the name of each constructor can always be computed as structname##_init, but I am not sure how to pass arbitrary constructor parameters after the this pointer through a macro in C. Anyhow, I prefer to avoid macros unless they are absolutely necessary, and in this case they are not.

c struct syntax with assignment?

I'm trying to get my head around structs. It seems ok in theory (e.g. a very concise and clear explanation: http://www.stanford.edu/class/cs110/hws/structs.html)
But then I find this in a code I'm messing with:
static struct pci_driver ik220_driver = {
name: DRV_NAME,
id_table: ik220_tbl,
probe: ik220_init_one,
remove: ik220_remove_one,
};
What does the = operator do here?
The = initializes a struct of type pci_driver, named ik220_driver, with the specified values for fields.
You are just assigning a variable, but it's a compound type.
Work it up in parts. struct pci_driver is a type. ik220_driver is a variable name. static sets the variable scope, so the rest: = {...} is specifying the value of the variable (which in this case happens to be a struct).

Problems with arrays of unspecified lengths

I'm writing an IrDA stack in c and implementing the Information Access Service component and i need a lookup table for class/key/value pairs. To keep it in an orderly format, I'm trying to put it all into one initialiser. the following code works just fine and compiles the data to compact linked tables in ROM.
#define IAS_PTYPE_STRING 0x00
#define IAS_PTYPE_BYTE 0x01
typedef struct {
UBYTE* name;
UBYTE type;
UBYTE* value;
} IAS_Attrib_t ;
typedef IAS_Attrib_t* IAS_Attrib_List_t[];
typedef struct {
UBYTE* name;
IAS_Attrib_List_t* attributes;
} IAS_Class_t;
static const IAS_Class_t IAS_Database[] = {
{"IrDA:IrCOMM",
&(IAS_Attrib_List_t){
&(IAS_Attrib_t){"Parameters", IAS_PTYPE_STRING, "IrDA:TinyTP:LsapSel"},
NULL,
},
},
};
However I'm having trouble getting the data back out. according to the types used, i should be able to do something like this:
UBYTE class = 1;
UBYTE attr = 1;
UBYTE* name = (*(IAS_Database[class].attributes))[attr]->name;
this is because
IAS_Database[class].attributes is type IAS_Attrib_List_t*
*(IAS_Database[class].attributes) is type IAS_Attrib_List_t i.e. IAS_Attrib_t*[]
(*(IAS_Database[class].attributes))[attr] should be type IAS_Attrib_t*
(*(IAS_Database[class].attributes))[attr]->name should be type UBYTE*
however when i try to query the table, i get invalid use of array with unspecified bounds back from mspgcc. Even a hack like (IAS_Attrib_t*)((IAS_Database[class].attributes)+(sizeof(IAS_Attrib_t)*attr)) fails until i cast the db to void like (IAS_Attrib_t*)((void*)(IAS_Database[class].attributes)+(sizeof(IAS_Attrib_t)*attr)) however this just feels so dirty. I'd really like to figure out the correct syntax to do it the right way.
Never mind.
In my utter frustration it seems i tried every variant bar the one I put up here. (*(IAS_Database[class].attributes))[attr] does indeed work properly and even works when expressed as (*IAS_Database[class].attributes)[attr] i believe the compiler was incorrectly assuming that the first pointer (being to a UBYTE**) was actually a list and was trying to apply the index to a pointer type (where the type is incomplete).
typedef IAS_Attrib_t* IAS_Attrib_List_t[];
why are you using these brackets ? use a number inside or remove them

Resources