this post was submitted on 18 Jun 2023
8 points (100.0% liked)

Programming

13373 readers
1 users here now

All things programming and coding related. Subcommunity of Technology.


This community's icon was made by Aaron Schneider, under the CC-BY-NC-SA 4.0 license.

founded 1 year ago
MODERATORS
 

Hello there, fellow programmers! I am an Aeronautical Engineering student who is doing research on Multidisciplinary Optimization (MDO) since the beginning of this year.

All the code I've written so far is in Python, but I want to move it to C so I can learn more about low level programming and so I can have more control over what my code actually does (since it is an MDO code, it needs to be very optimized because every 0.5 seconds added to each iteration add 500 seconds over 1000 iterations (9 minutes!)). I am taking an online course on C from edX, but I still cannot understand how to actually substitute objects for C compliant code. The main problem is that my original code uses lots of objects, and I simply do not know how to eliminate objects from my code.

Can someone help me? Any help is welcomed.

[edit] Thanks for all your answers, I think I'm getting it now.

top 9 comments
sorted by: hot top controversial new old
[–] [email protected] 12 points 1 year ago (2 children)

If your goal is to rewrite your python code in C with minimal hassle, start thinking of objects as structs with functions attached to them. If you detach the functions from the structs, instead having them take structs as an argument, then you can obtain something which is C-like but likely very unoptimised.

Personally, I think I would steer you towards Rust or C++ instead - both can run just as quickly, but have more OOP features and modern features which may make moving easier. Learning C is still a very good thing to do, but I'm not sure this project would be the best project to do that with.

[–] [email protected] 4 points 1 year ago (1 children)

I second everything said here. I would add that C++ might be a better candidate in this case as translating Python's OOP and Context Management would be more easily done in C++ than rust IMO. Thought it might involve a bit of template if your code heavily rely on duck typing, and you will have to get familiar with the weird move semantic of C++. Also make sure to activate ASAN and maybe UBSAN for the development phase and have an optimized build with debug symbols to run with valgrind (this is also valid if you decide to stick with C).

But if you're already familiar in rust, pick that.

Unless you have specific platform requirements, I would avoid C for any large projects nowadays. It's OK when learning low level stuff because it's one of the languages with the fewest abstraction layers, but this aspect becomes a weakness at scale. And especially when porting from higher level languages.

Also, something not mentioned yet, do you actually need to move everything to C? It might be that the core of the logic is only a few function that you can more easily translate to C and then call from ctypes or a native module. So you get to discover C for 80% of the benefits and 20% of the hassle.

[–] [email protected] 3 points 1 year ago

The main reason why one would want to use C is likely Foreign Function Interface (FFI), whatever code you write in C (apart from emitting assemblies) would likely be usable and extensible from any other programming languages so long that some of the conventions are followed. Rust and C++ could likely produce code just as fast as well optimized C code, but inaccessible or not readily accessible to other programming languages IE Name Mangling that are compiler implementation dependent, missing FFI access to STL and Traits and so forth.

FFI is pretty much the only reason why I am still writing in C in a very large project like GUI Toolkit to replace GTK and QT by using Vulkan. I would not recommend doing what I do when it come to implementing OOP manually in C to ensure that other programming language could extend my library. (I would write VTable manually and establish some of the OOP paradigms. C compiler does extremely well when optimizing out virtual dispatches to static dispatch.)

That's about it, as you said, it have a lot of hassles in C, so that why I am now working on Compiler Generator to create dialects on top of C similarly to MLIR so it would compile to readable C at the end of it as well as generating LSP server, FFI-JSON, and other things for it.

[–] [email protected] 1 points 1 year ago

Deep down, C++ class functions take a pointer to their objects as a first "invisible" parameter.

[–] [email protected] 7 points 1 year ago* (last edited 1 year ago) (1 children)

There are a many approaches to implementing OOP in C. Since C doesn’t give you any language constructs to implement this out of the box, it’s up to you to do it in a consistent and understandable manner. Since there is no definite way to do it, let me just give you an example of how I would translate a Python file, and you can decide how you implement it from there:

--------------
class Parent:
    def __init__(self, param1: str, param2: int):
        self.__param1 = param1
        self.__param2 = param2
    def __private_method(self):
        print("private method")
    def public_method(self):
        print("public method")
    @staticmethod
    def static_method():
        print("static method")
    @property
    def param1(self):
        return self.__param1

class Child(Parent):
    def __init__(self):
        super().__init__("param1", 2)
--------------

I would split the C code for this into header and source files:

(header.h)

--------------
#pragma once

/// Parent Class ///
typedef struct Parent_obj {
    char* param1
    unsigned int param1_len
    int param2
} Parent_obj_t;
void Parent_init(Parent_obj_t* self, char* param1, unsigned int param1_len, int param2);
void Parent_public_method(Parent_obj_t* self);
void Parent_static_method();
void Parent_param1(Parent_obj_t* self, char* out, unsigned int max_len); // property method with upper bound string length
void Parent_del(Parent_obj_t* self); // destruct object (similar to __del__() in python)

/// Child Class ///
typedef struct Child_obj {
    Parent_hidden_state_t* super
    char* param
    unsigned int param_len
} Child_obj_t
void Child_init(Child_obj_t* self, Parent_obj_t* super);
void Child_del(Child_obj_t* self);
--------------

(source.c)

--------------
#include "header.h"

/// Parent Class ///
// private methods
void Parent_private_method(Parent_obj){...}
// public methods
void Parent_init(Parent_obj_t* self, char* param1, unsigned int param1_len, int param2){...}
void Parent_public_method(Parent_obj_t* self){...}
void Parent_static_method(){...}
void Parent_param1(Parent_obj_t* self, char* out, unsigned int max_len){...}
void Parent_del(Parent_obj_t* self){...}

/// Child Class ///
// public methods
void Child_init(Child_obj_t* self, Parent_obj_t* super){...}
void Child_del(Child_obj_t* self){...}
--------------

Modules and namespaces can be modeled using folders and prefixing your structs and functions.

[–] [email protected] 1 points 1 year ago

This. Although I would argue it is a bad practice inherit from a class, only from an interface. GObject is your friend.

[–] [email protected] 0 points 1 year ago (1 children)

Is this community going to be for noon questions and people who won't read tutorials?

Just trying to decided if I should block it like the noob only programming reddits.

[–] [email protected] 2 points 1 year ago

I'm neither a mod nor an admin, but, as far as I know, all the communities on Beehaw are supposed to be very general and not too specific one way or another. This is due to the relatively low numbers of the platform.

load more comments
view more: next ›