Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Εμένα πάντως παιδιά, προβλήματα σαν κι αυτό μου "υπενθυμίζουν" γιατί προτιμώ τη C και το μη OOP για τέτοιες δουλειές. Βρίσκω την όλη υλοποίηση αχρείαστα πολύπλοκη και inefficient.

 

Ένα απλό...

 

>
struct ReslutType {
CommandSet_t cs;
int param;
};

struct ReslutType *parser = processInput( const char* inputdata, const int inputlen);

Είναι το μόνο που χρειάζεται σε HL για να γίνει η δουλειά που θέλει να κάνει. Η συνάρτηση processInput() θα φτιάχνει δυναμικά, θα γεμίζει και θα επιστρέφει έναν πίνακα από ResullType, από τον οποίο ο caller θα "τραβάει" ότι πληροφορία χρειάζεται και θα τον απελευθερώνει.

 

Αν δηλαδή δεν μου έχει διαφύγει πάλι κάτι στην εκφώνηση.

  • Απαντ. 54
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Συχνή συμμετοχή στο θέμα

Δημοσ.

Φίλε mig θα μου επιτρέψεις να διαφωνήσω.

 

Η πρώτη μου διαφωνία είναι στο ότι η υλοποίηση είναι πολύπλοκη και inefficient. Δυο μικρά interfaces ορίζει η εκφώνηση όλα κι όλα, συν μια class που ζητάει απο σένα. Δε νομίζω ότι αυτό λέγεται πολυπλοκότητα στην αρχιτεκτονική. Αν πάλι εννοείς πολυπλοκότητα στο implementation, αυτά που ανέλυα παραπάνω είναι προβλήματα που θα χρειαστεί να λυθούν ανεξάρτητα από το αν το implementation είναι σε C++, C, BASIC ή batch file -- επομένως είναι άδικο να λες ότι φταίει ο OOP.

 

Τώρα όσο για το inefficient, είναι ακριβώς το αντίθετο. Μόλις πρότεινες μια υλοποίηση που είναι κάργα inefficient γιατί κάνει parse όλη την είσοδο και επιστρέφει πίνακα. Και στη C++ αν θέλεις να το κάνεις αυτό επέστρεψε πίνακα, std::vector ή ο,τι άλλο θες. Το ζήτημα είναι πως αυτό δεν είναι efficient με τίποτα γιατί δεσμεύεις μνήμη για όλες τις parsed εντολές μαζί ενώ πρόκειται να τις χρησιμοποιήσεις μόνο μια-μια με τη σειρά. Εξάλλου η εκφώνηση σου λέει εμμέσως πλην σαφώς να μήν κάνεις ακριβώς αυτό το πράγμα -- επειδή παρόλο που είναι ευκολότερο να γραφτεί δεν είναι efficient.

 

Με την ίδια λογική θα μπορούσε κανείς να πει ότι είναι inefficient να μπλεκόμαστε με fread και βλακείες, ας υπήρχε μια freadeverything που να διαβάζει όλα τα περιεχόμενα του αρχείου σε ένα char[] και μετά όταν τελειώσεις ας τον κάνεις free. Ooops, το αρχείο δε χωράει όλο στη μνήμη, ή μόλις διαβάσαμε 100MB για να δούμε αν τα 4 πρώτα bytes είναι το τάδε magic number. Είναι ακριβώς η ίδια περίπτωση.

 

Σκέψου επίσης πόσο ζόρι θα πρέπει να τραβήξεις για να κάνεις implement κάτι με ισοδύναμο functionality σε C (ρητορική ερώτηση -- πολλές φορές έχεις χωθεί εδώ στο forum σε απίστευτα involved implementations πραγμάτων τα οποία με OO θα γινόταν πολύ πιο απλά στο γράψιμο κώδικα).

 

Νομίζω πως εδώ σε έπιασε η γνωστή πλάνη των προγραμματιστών που "έγιναν άντρες με τη C" και δεν απέκτησαν αργότερα αντίστοιχου βάθους εμπειρία σε OO γλώσσες: ο OOP είναι ένα εργαλείο που βοηθάει στη διαχείριση της πολυπλοκότητας. Όπως κάθε εργαλείο, υποτίθεται πως πρέπει να το χρησιμοποιείς όπου χρειάζεται, στο βαθμό που χρειάζεται και όχι όπου βρεις και μέχρι να ψοφήσει. Και επέτρεψέ μου να πιστεύω πως αν ήξερες OO τόσο καλά όσο ξέρεις C δε θα είχες την ίδια άποψη (έλα στην αντίθετη απο σένα θέση, κάποιου που μόλις έμαθε προγραμματισμό με Java: θα σκέφτεται ότι οι classes κάνουν τον ήλιο να λάμπει και τα πουλάκια να κελαηδάνε, κι αν έβλεπε τι κάνεις εσύ για να γράψεις ένα variant linked list σε C θα σε έλεγε τουλάχιστον ανώμαλο).

 

Πάντα φιλικά. :)

Δημοσ.

Μα δεν διαφωνώ στα περί της γενικότερης χρησιμότητας του OOP, ούτε επίσης διαφωνώ ότι προσωπικά αισθάνομαι πολύ πιο άνετα με τη C... όχι γιατί το παίζω "άντρας" όπως έγραψες, αλλά πολύ απλά επειδή στη μεγάλη πλειοψηφία της ενασχόλησής μου δούλεψα με C.

 

Επί του θέματος, όπως έγραψα και προχτές, το "efficiency" γενικώς κι αορίστως είναι τελείως σχετικός όρος. Η λύση που έγραψα είναι πολύ απλή και αποτελεσματική. Καταρχήν δεν διαβάζει όλο το input, αλλά από το inputdata έως το inputdata + inputlen (αυτό κατάλαβα πως μου είπατε σε προηγούμενα posts).

 

Δεύτερον, σου γλιτώνει ένα κάρο function calls, γιατί αν το έχω καταλάβει καλά η εναλλακτική είναι να επιστρέφεις ένα-ένα τα ResultType objects και να καλείς ξανά-μανά την processInput και όποιες άλλες συναρτήσεις καλεί μέσα της.

 

Τρίτον, η μνήμη που καταναλώνει ο πίνακας είναι αφενός πλήρως ελεγχόμενη (π.χ. θα μπορούσες να μη γυρίζεις όλο τον πίνακα μονοκόμματα αλλά μικρότερα τμήματά του κάθε φορά, και να ξανακαλείς την proceesInput() ... δηλαδή ως ενδιάμεση υλοποίηση μεταξύ αυτού που έγραψα κι αυτού που γράψατε (ζητάει; ) η άσκηση) και αφετέρου ακόμα και μονοκόμματη είναι πολύ λίγη σε απόλυτο μέγεθος ( 2 sizeof(int) per element... δηλαδή 100.000 elements είναι δεν είναι 800 Kb... αν τα int είναι 2bytes, τότε είναι δεν είναι 400Kb). Αν είσαι σε και απόλυτα ελεγχόμενο περιβάλλον και έχεις και περισσευάμενη μνήμη, το κάνεις και packed το struct για φορσέ alignment και του απογειώνεις και το speed).

 

Οπότε, τα πάντα είναι σχετικά ως προς το efficiency, δεν υπάρχει σωστό και λάθος. Υπάρχει όμως απλό και πολύπλοκο όπως υπάρχει και de-facto το γεγονός πως το implementation οποιουδήποτε OOP είναι κατά κανόνα και αργότερο και πιο μνημοβόρο (ανεξάρτητα δηλαδή από τους αλγόριθμους επίλυσης των προβλημάτων).

Δημοσ.

Εγώ την έχω κάνει και την έχω στείλει αλλα μου είπαν ότι άλλοι candidates την έλυσαν καλύτερα.. Φυσικά η υλοποίησή μου ήταν πολύ απλή γιατί δεν έδωσα ιδιαίτερη βάση στο efficiency.. Θα την ανεβάσω μόλις πάω σπίτι μαζί με το feedback που έλαβα από την εταιρία!

Δημοσ.

Την ασκησούλα την έστειλε τελικα κανείς? :D

 

p.s Καλησπέρα migf1 . Τα σέβη μου :D

 

Επ, γεια σου Κώστα! :)

 

Εγώ ούτε έστειλα, ούτε ασχολήθηκα, ούτε θα ασχοληθώ. Όχι πως τη σνομπάρω, το αντίθετο είναι πολύ ενδιαφέρουσα! Για μένα όμως η μόνη efficient all-around υλοποίηση είναι με real-time processing του κάθε χαρακτήρα κατά το parsing σε 1o draft, και κατόπιν επανεξέταση του κώδικα για επιπλέον optimization πάνω σε αυτή την υλοποίηση (όπως π.χ. κάποια από αυτά που έγραψα στο προηγούμενο post).

 

Το 1ο στάδιο από μόνο του θέλει να κάτσεις να ασχοληθείς με συγκέντρωση για αρκετή ώρα... το 2ο στάδιο θέλει ακόμα περισσότερη συγκέντρωση. Και δεν έχω διάθεση για τέτοια... αντί αυτού σχεδόν τελείωσα το i18n/l10n internationalization/localization της τρίλιζας σε GTK2 και τελειώνω μια σχεδόν εξ' ολοκλήρου αναθεώρηση του κώδικα του "Dates" (αφενός για να τον κάνω C89 από C99, κι αφετέρου διότι ήταν ολίγον για τα μπάζα :P).

 

Εγώ την έχω κάνει και την έχω στείλει αλλα μου είπαν ότι άλλοι candidates την έλυσαν καλύτερα.. Φυσικά η υλοποίησή μου ήταν πολύ απλή γιατί δεν έδωσα ιδιαίτερη βάση στο efficiency.. Θα την ανεβάσω μόλις πάω σπίτι μαζί με το feedback που έλαβα από την εταιρία!

 

Τελικά σου ξεκαθάρισαν αν δίνουν περισσότερο βάρος στο memory efficiency ή στο speed efficiency; Παρεμπιπτόντως μπορείς να γράψεις με 2-3 λόγια την προσέγγιση που ακολούθησες πριν ποστάρεις τον κώδικα (ή και χωρίς να ποστάρεις τον κώδικα).

Δημοσ.

@mig: Ναι και όχι.

 

Καταρχήν σ' ευχαριστώ που δεν με παρεξήγησες παρόλο που δεν πέρασα σωστά το μήνυμα πριν. "Έγινες άντρας" δεν εννοώ οτι το παίζεις άντρας, προς θεού -- το είπα με την έννοια ότι μαθαίνοντας καλά C (pointers, manual memory management κλπ) γίνεσαι σαν προγραμματιστής άντρας απο παιδάκι (τι είναι pointer? γιατί δηλαδή πρέπει να κάνω free? και πώς ξέρω πότε πρέπει να κάνω free? κλπ). Βάζω και τον εαυτό μου στην ίδια κατηγορία γιατί η πρώτη γλώσσα που μελέτησα σοβαρά ήταν η C++.

 

Τώρα για τα υπόλοιπα:

 

1. "Όλο το input" εννοώ όλο όσο σου είπαν να διαβάσεις (inputlen), προφανώς. Το υπόλοιπο είτε στο περάσουν είτε όχι δεν σε απασχολεί.

2. To function call σε x86 είναι αστεία γρήγορο οπότε δε νομίζω ότι έχει νόημα να συζητάμε για παραπανίσια function calls εκτός κι αν είναι π.χ. δισεκατομμύρια.

3. Αν γυρνάς τον πίνακα σε κομμάτια τότε μόλις έχεις κάνει iterator που είναι και η λύση που ζητάει η εκφώνηση και συζητάμε παραπάνω. Επίσης νομίζω πως δεν μας ενδιαφέρει εδώ το απόλυτο μέγεθος, γιατί στην ουσία έχουμε την εξής επιλογή: είτε parse όλες τις commands με iterator και κόστος μερικά function calls και constant memory footprint, είτε parse σε πίνακα με κόστος λιγότερα function calls και linear memory footprint.

 

Νομίζω η ζυγαριά γέρνει προς τον iterator ήδη από την εποχή του πρώτου 8088 γιατί όπως είπα το κόστος ανα function call είναι αστείο, ενώ σε embedded όσο λιγότερη μνήμη χρειάζεσαι τόσο καλύτερα γιατι μπορείς απλά να βάλεις λιγότερη physical RAM πάνω στο σύστημα (μικρότερο κόστος, λιγότερη κατανάλωση ενέργειας). Στο τωρινό desktop μου με 8GB RAM τα 400k δε φαίνονται και πολύ, αλλά στο πρώτο μου desktop με 4M ήταν το 10% της συνολικής RAM!

 

Τέλος για την κατακλείδα σου θα πω ότι τεχνικά έχεις δίκιο στις περισσότερες των περιπτώσεων (όχι πάντα), αλλά:

 

1. Πρόσεχε μη συγκρίνεις μήλα με πορτοκάλια. Αν η procedural και η OOP λύση δεν προσφέρουν το ίδιο επίπεδο abstraction η σύγκριση δεν έχει νόημα.

2. Η διαφορά σε ταχύτητα και κατανάλωση μνήμης κατ' απόλυτη τιμή είναι τόσο μικρή που δεν έχει νόημα γιατί γίνεται dominate από άλλους παράγοντες πρακτικά πάντα.

3. Αν μου ανέθεταν να κάνω maintain το ίδιο περίπλοκο πρόγραμμα σε OOP και σε pure C θα έπαιρνα το πρώτο και θα λυπόμουν τον καημένο που πήρε το δεύτερο. Και γι' αυτό χρησιμοποιούμε όπως είπα OOP: μοντελοποίηση => μείωση πολυπλοκότητας => ευκολότερη κατανόηση του συστήματος => λιγότερα bugs και μικρότερο κόστος.

 

Χωρίς να θέλω σε καμία περίπτωση να μειώσω τη σημαντικότητα και τα πλεονεκτήματα γλωσσών όπως η C, έχω την άποψη πως όσο προχωράει η τεχνολογία τα πλεονεκτήματα αυτά γίνονται όλο και λιγότερο σημαντικά. Και συγκεκριμένα πιστεύω πως σήμερα είναι τόσο λίγο σημαντικά αν δεις σφαιρικά τον κόσμο που δεν πρόκειται κανείς στα λογικά του να προτείνει σα rule of thumb τη μη χρήση OOP για οποιοδήποτε πρόγραμμα που δεν είναι trivial.

 

Κλείνω με κάτι που ανέφερα και νωρίτερα: πιστεύω (χωρίς να ξέρω) πως δεν έχεις γνωρίσει τον OOP στο βαθμό που χρειάζεται για να δεις την ομορφιά του όπως ήδη βλέπεις την ομορφιά της C.

Δημοσ.

Εγώ την έχω κάνει και την έχω στείλει αλλα μου είπαν ότι άλλοι candidates την έλυσαν καλύτερα.. Φυσικά η υλοποίησή μου ήταν πολύ απλή γιατί δεν έδωσα ιδιαίτερη βάση στο efficiency.. Θα την ανεβάσω μόλις πάω σπίτι μαζί με το feedback που έλαβα από την εταιρία!

 

 

Τους ρώτησες τι σημαίνει το "καλύτερα" ????

 

Το να ειναι κατι πολυ απλο αλλα ταυτοχρονα να απανταει στην ερωτηση

 

δεν ειναι κακο ξερεις.

Δημοσ.

Θυμάμαι και εγώ μια εταιρία που σου εδινε πέντε ώρες να φτιάξεις κάτι προγράμματα !!! Δεν ήξερες φυσικά τι είναι μέχρι να πατήσεις το κουμπί ! Ε δεν το πάτησα καν. :)

Δημοσ.

Θυμάμαι και εγώ μια εταιρία που σου εδινε πέντε ώρες να φτιάξεις κάτι προγράμματα !!! Δεν ήξερες φυσικά τι είναι μέχρι να πατήσεις το κουμπί ! Ε δεν το πάτησα καν. :)

 

 

Εργαζόμενους ψάχνανε φίλε μου ή παπατρέχηδες? :D

Δημοσ.

@defacer:

 

Όλα τα είδη προγραμματισμού (τα 3 βασικά δηλαδή: procedural, oop & functional) έχουν τα υπέρ και τα κατά τους, αλλά και τα 3 έχουν θέση και χρησιμότητα, λόγω του τεράστιου εύρους της πληροφορικής. Για αυτό και συνυπάρχουν αρμονικά επί 10ετίες ολόκληρες και προσωπικά πιστεύω θα συνεχίσουν. Απλώς αλλάζει ο βαθμός επικαιροποίησης τους κατά εποχές. Κανένα τους όμως δεν αποτελεί πανάκεια.

 

Έχω την εντύπωση πως κινείσαι στον ακαδημαϊκό χώρο (έτσι έχω καταλάβει από τα συμφραζόμενα) οπότε ίσως ξέρεις ήδη πως στο Carnegie βγάζουν (έβγαλαν) το OOP από την ύλη των πρώτων εξαμήνων, ως αναχρονιστικό τρόπο μιας και το μέλλον οδεύει προς το parallelization (το οποίο εκ φύσεως δεν ευνοείται από το OOP).

 

Σχετικά με τα function-calls, δεν ξέρουμε για τι είδους embedded πλατφόρμα μιλάμε. Οπότε κατά την ταπεινή μου άποψη ότι assumption και να κάνουμε είναι εξ' ορισμού άστοχο, και δυστυχώς δεν μπαίνουν στον κόπο να το διευκρινίσουν εκεί στη Light Modeling.

 

Περί memory-footprint, η διαφορά μεταξύ procedural και oo programming είναι έως και χαώδης ... ξανά εξ' ορισμού. Περί μήλων & πορτοκαλιών, δεν συνέκρινα, όμοιες υλοποιήσεις σε C και C++, απλώς επεσήμανα πως εφόσον μιλάει για efficiency και για ενσωματωμένα συστήματα, η C για τη συγκεκριμένη δουλειά που θέλει να κάνει θα ήταν πολύ καλύτερη επιλογή και ως γλώσσα και ως προσέγγιση. Μου φάνηκε δηλαδή κάπως σαν "αστείο" από τη μια μεριά να απαιτεί efficiency κι από την άλλη μεριά να το ζητάει σε C++ και συγκεκριμένα με OOP API.

 

Για τον iterator, η βασικά διαφορά μεταξύ της δικής σας πρότασης και της δικής μου ήταν πως εσείς εστιάσατε αποκλειστικά στην επιστροφή ενός μόνο object per iteration ενώ εγώ του έδωσα τη δυνατότητα να επιστρέφει όσα πολλά ή όσο λίγα objects επιτάσσει το όποιο efficiency χρειάζεται ο user per iteration.

 

Πάντως και μένα αν μου έλεγαν να επιλέξω μεταξύ OOP και procedural project για να κάνω maintain, μάλλον OOP θα διάλεγα. Βέβαια και τα 2 είδη μπορούν να παράξουν εξίσου δυσανάγνωστο και ευανάγνωστο κώδικα, είναι καθαρά στο χέρι των προγραμματιστών τους.

 

Σε γενικές γραμμές, πάντως (εννοώ στην γενικότερη συμμετοχή μας στο φόρουμ) συμφωνούμε στην πλειοψηφία των περιπτώσεων, παρά διαφωνούμε ;) Πρέπει και να διαφωνούμε πάντως αλλιώς καταντάει βαρετό :lol:

 

Κλείνω με κάτι που ανέφερα και νωρίτερα: πιστεύω (χωρίς να ξέρω) πως δεν έχεις γνωρίσει τον OOP στο βαθμό που χρειάζεται για να δεις την ομορφιά του όπως ήδη βλέπεις την ομορφιά της C.

Το ότι κατά συντριπτική πλειοψηφία επιλέγω να συμμετάσχω σε μη OOP νήματα προφανώς και ΔΕΝ είναι τυχαίο ;) Σαφώς και δεν τον γνωρίζω στο βάθος που θα ήθελα, και σίγουρα σε καμία περίπτωση στο βάθος που γνωρίζω τη C.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...