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

Γενικό thread αποριών για τη C#.


Alithinos

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

Υποθέσεις; μάλλον εννοείς  ελέγχους (τα IF δεν κάνουν υποθέσεις, εκτελούν ελέγχους)

Έστω ότι βελτιώθηκε η δουλειά για σένα, στο κομμάτι του αλγόριθμου δεν έχουμε τίποτα όμως!

Αυτό που πρότεινα παραπάνω είναι να μην πηγαίνεις σειριακά...δηλαδή να ομαδοποιήσεις αν γίνεται τις 120 υποθέσεις και να έχεις μια ιδιότητα σε κάθε αντικείμενο "υποθέσεως"...που θα λέει αν δεν πετύχει σε ποια υπόθεση θα συνεχίσει.

Τότε αντί να εκτελείς 120 υποθέσεις...θα πηγαίνεις σαν να εκτελείς βάσει δυαδικού δένδρου. Χτίζεις το δένδρο..ξερά και ωραία...(εδώ θέλει ένα πλάνο και να ετοιμάσεις βελάκια). Να γιατί συζητώ για struct, Τα βάζεις σε πίνακα και στην ιδιότητα που αναφέρω βάζεις την τιμή του επόμενου προς έλεγχο στον Κ struct.

κάθε data θα βγαίνει μετά από μια σειρά ελέγχους το πολύ π.χ. 10 struct. Αν το έχεις με γραμμικό τρόπο τότε η καλύτερη έχει πιθανότηα 1 στις 120 να έρθει...όπως και η χειρότερη,  και αν υποθέσουμε ότι έχεις μοιρασμένα τα δεδομένα, πχ ότι κάθε υπόθεση όντως έχει 1/120 πιθανότητες να έρθει τότε ο μέσος χρόνος θα είναι 60 έλεγχοι...

Μια παρόμοια συλλογιστική θα έδειχνε ότι η αναβάθμιση του προγράμματος έχει αξία, ενώ τώρα δεν αλλάζεις κάτι στο ουσιαστικό, απλά σκέφτεσαι ότι το copy paste δεν βολεύει...(αντίθετα βολεύει θα έλεγα)...και ας έχεις 1000 γραμμές.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

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

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

Δημοσιευμένες Εικόνες

Kercyn,

μιλάει για την εισαγωγή κώδικα, αν πούμε ότι αυτός είναι το πρόγραμμα εισαγωγής εντιολών!!!!!!!

Το πρόγραμμά του δεν έχει αλλάξει ουσιαστικά, δεν κερδίζει κάτι αυτό του έγραψα. 

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ενδιαφέρον φαίνεται. Θα το έχω στο νου μου για αργότερα. Νομίζω πως θα ήταν καλύτερο να μάθω πρώτα ακόμα καλύτερα τη C#, ή δεν είναι έτσι ?

 

Χμμ, αυτό σκέφτηκα και εγώ. Πως θα έπρεπε να αναλώσω περισσότερο χρόνο. Αλλά ξέρεις τι ? Νομίζω πως μερικά πράγματα ίσως είναι πιο δύσκολο να τα προνοήσεις, από το να τα βρεις ενώ γράφεις το κώδικα. Σίγουρα άμα αφιέρωνα περισσότερο χρόνο θα σκεφτόμουν και καλύτερα, και θα σημείωνα και περισσότερες λεπτομέρειες, αλλά είναι και αυτός ο ενθουσιασμός που αποκτάς όταν πιστεύεις ότι βρήκες τη λύση, πως να κάνεις κάτι, και θες ευθύς αμέσως να βουτήξεις και να αρχίσεις να το φτιάχνεις...

Θα προσπαθήσω από δω και πέρα να αναλύω πιο διεξοδικά το κάθε project πριν αρχίσω το γράψιμο.

 

Έχεις να προτείνεις κάποιες πηγές ?

 

 

Anti-design ?  :o

Υπάρχει και αυτό ? 

Βασικά η πρώτη ιδέα που θα έρθει για μια υλοποίηση, δεν είναι πάντα η καλύτερη. Η χαρά όμως που παίρνεις επειδή βρήκες πως να το κάνεις να κάνει αυτό που θες, να δουλεύει, μπορεί να κάνει να μη σκεφτείς εκείνη τη στιγμή ότι υπάρχει και ακόμα καλύτερος τρόπος, και να αρχίσεις να το υλοποιείς με αυτό τον τρόπο επειδή 'δουλεύει', και επειδή είσαι ακόμα χαρούμενος και έχεις αυτό το αίσθημα ικανοποίησης, να έχεις για όσο κρατά αυτός ο ενθουσιασμός τη ψευδαίσθηση ότι και ο τρόπος αυτός είναι πραγματικά καλός / αρκεί. Μετά από μερικές μέρες που σου χει περάσει αυτό το συναίσθημα και συνεχίζεις να υλοποιείς, σκέφτεσαι "Μα για κάτσε... Αφού αυτό μπορώ να το κάνω και με τον άλλο τρόπο, και ο άλλος τρόπος ενδεικνίεται ακριβώς για αυτή τη περίπτωση... Γιατί παιδεύω τον εαυτό μου έτσι ?"

 

Άρα είναι λογικό να κάνω τέτοια λαθάκια ε ? Ωραία!  :lol:

Χαίρομαι για αυτό.

 

Άρα λοιπόν το μυστικό είναι εργασία και χαρά και μπόλικη εξάσκηση!

Θα τα καταφέρω, που θα πάει...

 

 

 

Υ.Γ. Τελικά μπόρεσα να το κάνω να δουλέψει και μετά το τελευταίο refactor, που με μπέρδεψε. Χθες το βράδυ που προσπαθούσα είχα κολλήσει απίστευτα. Ίσως να είχε κουραστεί και το μυαλό μου από τη μέρα, και να έφταιγε και το ότι ήταν βράδυ...

Με βοήθησε όμως πάρα πολύ η λειτουργία του Virtual Studio που βάζεις τη κόκκινη τελείτσα και εκτελείται ο κώδικας βήμα - βήμα, βλέποντας τι τιμές παίρνουν οι μεταβλητές σε κάθε βήμα.

Χρυσό feature.

Το (αστείο ?) της υπόθεσης είναι ότι σήμερα, με το νέο σχεδιασμό / refactor πλέον, έφτασα το πρόγραμμα σε 1 ημέρα σε επίπεδο που κατά τη πρώτη μου υλοποίηση μου είχε πάρει πάνω από 10 μέρες να το φτάσω. Έχω ήδη γράψει τις βασικές κλάσεις και μεθόδους που πράττουν στα δεδομένα, και εισήγαγα τα δεδομένα για τις πρώτες 8 "περιπτώσεις"!

Ενώ στη δουλειά που είχα κάνει στη πρώτη υλοποίηση που μου πήρε πάνω από βδομάδα, είχα φτάσει μέχρι τις 24 περιπτώσεις.

 

 

Υ.Γ.2. Βασικά ο αρχικός τρόπος εισαγωγής δεδομένων είχε ως εξής: Για κάθε 'περίπτωση' χρειαζόμουν τουλάχιστον 5 τιμές σε συναρτήσεις άλγεβρας boolean, που έβαζα μέσα σε if/elsif, 1 if/elseif για κάθε περίπτωση, οι οποίες if/elseif ήταν με τη σειρά τους μέσα σε κάποιο case μιας switch, γιατί μιλάμε για περίπτωση της περίπτωσης... Συν του ότι έβαζα απόλυτες τιμές σε κάθε if/elseif, δηλαδή πραγματικούς literal αριθμούς.

Έτσι έγραφα μέσα σε κάθε case μια συστοιχία από if/elseif, βάζοντας στις συνθήκες των if/elseif χειροκίνητα τις πραγματικές τιμές.

Ο νέος τρόπος έχει ως εξής: Έφτιαξα μια κλάση για τη κάθε 'περίπτωση', η οποία έχει και τον Constructor της, ώστε να δέχεται απ' ευθείας τιμές κατά την αρχικοποίηση. Ο έλεγχος αντί να γίνεται με πολλαπλές if/elseif και με literal τιμές όπου η κάθε if/elseif θα λειτουργεί μόνο για μια περίπτωση, γίνεται με overloaded operator, και αντί για literal τιμές ορίζονται με ονόματα μεταβλητών που αποκτάν τις τιμές τους κατά την αρχικοποίηση και δημιουργία του αντικειμένου, που σημαίνει πως υπάρχει μόνο μια φορά γραμμένη μια if και μια else, και δεν χρειάζεται να φτιάχνω διαφορετικές if/elseif για κάθε αντικείμενο / υπόθεση.

Έτσι το μόνο που έχω να κάνω πλέον για τη προσθήκη κάθε νέας περίπτωσης είναι να φτιάξω και να αρχικοποιήσω ένα νέο αντικείμενο, δηλαδή να γράψω 1 σειρά κώδικα!  :D  Όχι ολόκληρα κατεβατά!

 

 

 

alithinos... πρόσεχε γιατί πας προς Μ2000.... 

 

 

Επίσης, αυτό που έκανες (εάν το κατάλαβα καλά) δεν είναι ΟΟΡ αλλά κάτι που δεν ξέρω πως λέγεται... 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Υποθέσεις; μάλλον εννοείς  ελέγχους (τα IF δεν κάνουν υποθέσεις, εκτελούν ελέγχους)

Δεν χρησιμοποίησα τη λέξη "υποθέσεις" σαν προγραμματιστικό όρο, αλλά με τη μη-προγραμματιστική, γενική, κυριολεκτική ετυμολογία της.  :)

Για παράδειγμα:

 

Αν ρίξεις ένα ζάρι, υπάρχουν έξι υποθέσεις.

Στη κάθε υπόθεση, ο αριθμός που φαίνεται στη κορυφή του ζαριού είναι διαφορετικός.

 

 

Έστω ότι βελτιώθηκε η δουλειά για σένα, στο κομμάτι του αλγόριθμου δεν έχουμε τίποτα όμως!

Αυτό που πρότεινα παραπάνω είναι να μην πηγαίνεις σειριακά...δηλαδή να ομαδοποιήσεις αν γίνεται τις 120 υποθέσεις και να έχεις μια ιδιότητα σε κάθε αντικείμενο "υποθέσεως"...που θα λέει αν δεν πετύχει σε ποια υπόθεση θα συνεχίσει.

Τότε αντί να εκτελείς 120 υποθέσεις...θα πηγαίνεις σαν να εκτελείς βάσει δυαδικού δένδρου. Χτίζεις το δένδρο..ξερά και ωραία...(εδώ θέλει ένα πλάνο και να ετοιμάσεις βελάκια). Να γιατί συζητώ για struct, Τα βάζεις σε πίνακα και στην ιδιότητα που αναφέρω βάζεις την τιμή του επόμενου προς έλεγχο στον Κ struct.

κάθε data θα βγαίνει μετά από μια σειρά ελέγχους το πολύ π.χ. 10 struct. Αν το έχεις με γραμμικό τρόπο τότε η καλύτερη έχει πιθανότηα 1 στις 120 να έρθει...όπως και η χειρότερη,  και αν υποθέσουμε ότι έχεις μοιρασμένα τα δεδομένα, πχ ότι κάθε υπόθεση όντως έχει 1/120 πιθανότητες να έρθει τότε ο μέσος χρόνος θα είναι 60 έλεγχοι...

Μια παρόμοια συλλογιστική θα έδειχνε ότι η αναβάθμιση του προγράμματος έχει αξία, ενώ τώρα δεν αλλάζεις κάτι στο ουσιαστικό, απλά σκέφτεσαι ότι το copy paste δεν βολεύει...(αντίθετα βολεύει θα έλεγα)...και ας έχεις 1000 γραμμές.

 

Κάτι είναι όμως και να βελτιωθεί η δουλειά για εμένα. Έχει και αυτό μια αξία.

Χμ κοίτα με τα δυαδικά δένδρα (και τους γράφους) δεν έχω εμπειρία ακόμα. 

Ξέρω τη βασική έννοια των "Διαίρε και Βασίλευε", αλλά συγκεκριμένα την υλοποίηση του δένδρου δεν την έχω εξασκήσει ακόμα.

Προς το παρόν έχω εξοικειωθεί με τους Πίνακες, τις Ουρές, τις Στοίβες, και τις Συνδεδεμένες Λίστες.

Αυτό που έκανα ήταν να βάλω το κάθε αντικείμενο σε ένα Πίνακα, και με τη χρήση foreach να χρησιμοποιώ για κάθε αντικείμενο του πίνακα τον υπερφορτωμένο τελεστή να δω αν η υπόθεση (τα δεδομένα εισαγωγής του χρήστη) ανήκουν σε κάποια από τις 'υποθέσεις' που έχω φτιάξει.

Δεν ξέρω τι ακριβώς έχεις κάνει αλλά O(n) = O(8n).

 

Όπως έγραψε ο Μ2000, δεν το ανέφερα για τον αλγόριθμο με τον οποίο λειτουργεί το ίδιο το πρόγραμμα, αλλά με τον αλγόριθμο τον οποίο ακολουθώ και εκτελώ εγώ για να εισάγω τα στοιχεία.

Αυτό που ήθελα να πω είναι πως πριν το τελευταίο refactor, για κάθε στοιχείο n που ήθελα να προσθέσω, όπου εδώ το n είναι η κάθε πιθανή 'περίπτωση', στην οποία τα δεδομένα εισόδου μπορούν να εμπίπτουν, έπρεπε να γράφω 8 γραμμές, ενώ πλέον γράφω 1 γραμμή. Έτσι η μαθηματική σχέση γραμμών κώδικα που θα έπρεπε να γράψω για ένα n αριθμό, είχε αναλογία 8 προς 1.

Για κάθε στοιχείο χρειαζόμουν 8 γραμμές, δηλαδή για 1 στοιχείο 8 γραμμές, για 10 στοιχεία 800 γραμμές..

Ενώ μετά το refactor η μαθηματική σχέση γραμμών ανά υπόθεση είναι 1 προς 1.

Αυτό κάνει την εισαγωγή "περιπτώσεων" πολύ πιο γρήγορη, θα τελειώσω την εισαγωγή τους στο 1/8 του χρόνου που θα μου έπαιρνε πριν το refactor.

alithinos... πρόσεχε γιατί πας προς Μ2000.... 

Γιατί το λες αυτό ?  :o

 

 

 

Επίσης, αυτό που έκανες (εάν το κατάλαβα καλά) δεν είναι ΟΟΡ αλλά κάτι που δεν ξέρω πως λέγεται... 

 

Χμμ...  :mellow:

Αυτό που έκανα, είναι το εξής:

 

Αρχικά, πριν το τελευταίο refactor είχα κάποιες κλάσεις, και σε μια συγκεκριμένη κλάση είχα μια μέθοδο, και μέσα σε αυτή τη μέθοδο η οποία σκοπό είχε να ελέγξει δεδομένα εισόδου από το χρήστη ώστε να δει σε ποια από τις προκαθορισμένες 'περιπτώσεις' που έχω εισαγάγει εγώ ανήκουν. Αυτό όμως γινόταν με έναν πολύ 'χύμα' και 'in your face' τρόπο, όπου για να βρεθεί το σε ποια περίπτωση αντιστοιχούν τα δεδομένα του χρήστη, είχα μια τεράστια συστοιχία από if/elseif. 

 

Αυτό όμως είχε 2 σοβαρά προβλήματα:

 

1) Έπρεπε για κάθε 'περίπτωση' να κάνω copy paste μια συνάρτηση boolean, και να γράφω τις εντολές (statements) για το τι θα γίνει αν η boolean είναι true, σε κάθε if/elseif. Σκέψου 8 σειρές ανά περίπτωση.

 

2) Αρκετά σύντομα το πρόγραμμα άρχισε να γίνεται δυσανάγνωστο. Φαντάσου αφού έχω σκοπό να ελέγχω τα δεδομένα εισόδου για τουλάχιστον 120 περιπτώσεις, να έχω 120 if/elseif, με 8 γραμμές οι κάθε μια. Ακόμα και αν κρύβεις τη κάθε περίπτωση με #region & #endregion, γίνεται πολύ cluttered.

 

Αποφάσισα λοιπόν να λύσω αυτά τα προβλήματα, και να μειώσω δηλαδή τον αριθμό γραμμών που έπρεπε να γράψω, απ τη μια για να τελειώσω και την ολοκλήρωση των 120 υποθέσεων πιο γρήγορα, και από την άλλη για να μη γίνεται ένας χαμός με 960 σειρές κώδικα μέσα σε μια μόνο μέθοδο, και χάνει η μάνα το παιδί και το παιδί τη μάνα...

 

Αυτά τα προβλήματα τα έλυσα με τον εξής τρόπο:

 

α) Δημιούργησα μια κλάση η οποία θα αποτελεί το πρότυπο για τη κάθε περίπτωση, ώστε να ενθυλακώσω μέρος του κώδικα να μη φαίνεται σκόρπιος.

β) Έβαλα στη κλάση constructor, ώστε να μπορώ να θέσω τις τιμές κάθε προκαθορισμένης 'περίπτωσης' (του object αυτής της κλασης στη συγκεκριμένη περίπτωση) σε μια γραμμή, κατά την αρχικοποίηση και δημιουργία του αντικειμένου.

γ) Έκρυψα τους πολύπλοκους ελέγχους boolean και τα statements που ορίζουν τι θα γίνει αν boolean = true ή boolean = false, σε γενικής χρήσης υπερφορτωμένο τελεστή, προκειμένου απ τη μια να ενθυλακώσω και να κρύψω τις λεπτομέρειες υλοποίησης να μη φαίνονται χύμα, και από την άλλη να κάνω reuse κώδικα που χρειαζόταν να εκτελεστεί για τη κάθε περίπτωση.

 

Έτσι, από εκεί που πριν έπρεπε για κάθε 'περίπτωση' να γράφω 8 σειρές, τώρα χρειάζεται να γράφω μια, συγκεκριμένα μια σειρά όπου αρχικοποιώ ένα αντικείμενο ανά κάθε περίπτωση.

Και αντί να έχω μια μέθοδο με 120 if/elseif, έχω μια μέθοδο με ένα Πίνακα 120 αντικειμένων, και μια foreach που ελέγχει το κάθε στοιχείο του πίνακα με τον υπερφορτωμένο τελεστή.

 

Συμπερασματικά δηλαδή η αλλαγή:

 

A) Προσέθεσε περισσότερη ενθυλάκωση, περισσότερο abstraction, κάνοντας το κώδικα πιο ευανάγνωστο.

Β) Αύξησε την επαναχρησιμοποίηση κώδικα, για να μη κάθομαι να κάνω copy paste ξανά και ξανά.

 

 

Έχω λοιπόν την υποψία ότι έτσι το πρόγραμμα έγινε πιο αντικειμενοστραφή από ότι ήταν πριν. Γιατί ενθυλακώνονται πράγματα που πριν ήταν χύμα, προσφέροντας τα οφέλη που προσφέρει η ενθυλάκωση.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

 

Έτσι, από εκεί που πριν έπρεπε για κάθε 'περίπτωση' να γράφω 8 σειρές, τώρα χρειάζεται να γράφω μια, συγκεκριμένα μια σειρά όπου αρχικοποιώ ένα αντικείμενο ανά κάθε περίπτωση.

 

...

 

Έχω λοιπόν την υποψία ότι έτσι το πρόγραμμα έγινε πιο αντικειμενοστραφή από ότι ήταν πριν. Γιατί ενθυλακώνονται πράγματα που πριν ήταν χύμα, προσφέροντας τα οφέλη που προσφέρει η ενθυλάκωση.

 

Απο τα λεγόμενα σου, έχεις κάνει όλο το refactoring, για να φέρεις τον κώδικά σου σε αντικειμενοστραφή μορφή και πολύ καλά έκανες, διότι με το encap, έπαψες να επαναλαμβανεσαι και το DRY είναι βασική αρχή στον προγραμματισμό. Αν κατανοηθεί σωστά, δε σ'αφήνει να γράψεις το ίδιο πράγμα 2 φορές, ούτε με διαφορετικό κώδικα.

 

Απο την άλλη όμως ανάλογα με την εφαρμογή, μπορεί να επηρεάσεις δραματικά το performance (βλ. Duff's device - ο τύπος έκανε ακριβώς το ανάποδο το '70! -), οπότε ΙΜΗΟ όλα θέλουν μέτρο.

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Anti-design ?  :o

Υπάρχει και αυτό ?

Anti-design συγκεκριμένα δεν έχω ακούσει (έτσι μου προέκυψε) αλλά προήλθε από τον πολύ διαδεδομένο όρο antipattern.

 

https://en.wikipedia.org/wiki/Anti-pattern

 

Βασικά η πρώτη ιδέα που θα έρθει για μια υλοποίηση, δεν είναι πάντα η καλύτερη. Η χαρά όμως που παίρνεις επειδή βρήκες πως να το κάνεις να κάνει αυτό που θες, να δουλεύει, μπορεί να κάνει να μη σκεφτείς εκείνη τη στιγμή ότι υπάρχει και ακόμα καλύτερος τρόπος, και να αρχίσεις να το υλοποιείς με αυτό τον τρόπο επειδή 'δουλεύει', και επειδή είσαι ακόμα χαρούμενος και έχεις αυτό το αίσθημα ικανοποίησης, να έχεις για όσο κρατά αυτός ο ενθουσιασμός τη ψευδαίσθηση ότι και ο τρόπος αυτός είναι πραγματικά καλός / αρκεί. Μετά από μερικές μέρες που σου χει περάσει αυτό το συναίσθημα και συνεχίζεις να υλοποιείς, σκέφτεσαι "Μα για κάτσε... Αφού αυτό μπορώ να το κάνω και με τον άλλο τρόπο, και ο άλλος τρόπος ενδεικνίεται ακριβώς για αυτή τη περίπτωση... Γιατί παιδεύω τον εαυτό μου έτσι ?"

 

Άρα είναι λογικό να κάνω τέτοια λαθάκια ε ? Ωραία!  :lol:

Χαίρομαι για αυτό.

Αυτό που περιγράφεις, όπως το περιγράφεις, είναι απόλυτα φυσιολογικό και θα έλεγα μάλιστα και καλό σημάδι.

 

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

 

Δεν κέρδισες τίποτα όμως! Αυτά τα αντικείμενα δεν θα χρησιμοποιηθούν αλλού, αρα δεν υπήρχε λόγος να γίνουν. Θα μπορούσες να είχες struct σε πίνακα και να περνάς κάθε struct από μια διαδικασία ελέγχου.

 

Ουδέν σχόλιο...

 

Απο την άλλη όμως ανάλογα με την εφαρμογή, μπορεί να επηρεάσεις δραματικά το performance (βλ. Duff's device - ο τύπος έκανε ακριβώς το ανάποδο το '70! -), οπότε ΙΜΗΟ όλα θέλουν μέτρο.

 

Θα μπορούσε να γράψει κανείς τόμους εδώ (Dijkstra optimization κλπ) αλλά θα πω μόνο το πρακτικό: είναι καλό να μπορείς να σκεφτείς πώς να κάνεις ένα πρόγραμμα πιο γρήγορο, αλλά δεν είναι πολύ χρήσιμο. Το να είναι ξεκάθαρο και σωστά δομημένο είναι πολύ πολύ χρησιμότερο.

  • Like 2
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Απο τα λεγόμενα σου, έχεις κάνει όλο το refactoring, για να φέρεις τον κώδικά σου σε αντικειμενοστραφή μορφή και πολύ καλά έκανες, διότι με το encap, έπαψες να επαναλαμβανεσαι και το DRY είναι βασική αρχή στον προγραμματισμό. Αν κατανοηθεί σωστά, δε σ'αφήνει να γράψεις το ίδιο πράγμα 2 φορές, ούτε με διαφορετικό κώδικα.

 

Απο την άλλη όμως ανάλογα με την εφαρμογή, μπορεί να επηρεάσεις δραματικά το performance (βλ. Duff's device - ο τύπος έκανε ακριβώς το ανάποδο το '70! -), οπότε ΙΜΗΟ όλα θέλουν μέτρο.

Το πήρα πριν λίγες μέρες το βιβλίο τους.  :)

Έχω φτάσει ως τη συμβουλή #10.

Anti-design συγκεκριμένα δεν έχω ακούσει (έτσι μου προέκυψε) αλλά προήλθε από τον πολύ διαδεδομένο όρο antipattern.

 

https://en.wikipedia.org/wiki/Anti-pattern

 

Ενδιαφέρον το λινκ με τα anti-patterns. Έχει να πέσει αρκετό διάβασμα. (y)

 

 

Αυτό που περιγράφεις, όπως το περιγράφεις, είναι απόλυτα φυσιολογικό και θα έλεγα μάλιστα και καλό σημάδι.

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

 

 

^_^

Έχει να πέσει refactoring τότε...

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ενδιαφέρον το λινκ με τα anti-patterns. Έχει να πέσει αρκετό διάβασμα. (y)

 

Φρόντισε να ισορροπείς το διάβασμά σου με development. Τις περισσότερες λύσεις (λέω "λύσεις" γιατί βολεύει στην πρόταση, αλλά δεν εννοώ "λύσεις" με τη στενή έννοια, θα μπορούσα να πω "πράγματα") δε μπορείς να τις εμπεδώσεις αν δεν έχεις πρώτα ανακαλύψει το πρόβλημα. Τυπικά η ανακάλυψη γίνεται the hard way, και τότε είσαι έτοιμος να αφομοιώσεις τη λύση που θα βρεις μελετώντας.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Χεχ, κλασικό είδος ερώτησης.
 
Προσπερνάω τα προφανή "τεχνικά" σενάρια με μια απλή αναφορά:

  • Ο τύπος και ο αριθμός των παραμέτρων του indexer μπορεί να καθοριστεί όπως σου αρέσει. Αν θες να κάνεις foo[5.2, "miles", Direction.North] (ο,τι κι αν σημαίνει αυτό) δε σε εμποδίζει κανείς. Με πίνακα δε μπορείς.
  • Μπορείς να έχεις πολλούς (overloaded) indexers στην ίδια class.

Η αλήθεια είναι πως δεν είναι και πολύ πειστικά τα παραπάνω έτσι κι αλλιώς. Αν είναι μόνο για getter τότε είσαι πολύ καλύτερα γράφοντας μια method αντί για τέτοιο περίεργο indexer, και το να έχεις setter σε τέτοιο περίεργο indexer είναι σούπερ σπάνιο (δεν έχω δει ποτέ μου) και ενδεχομένως δείγμα ύποπτου σχεδιασμού. Συν ότι θα μπορούσε να υλοποιηθεί το ίδιο πράγμα με διαφορετική σύνταξη που συνήθως θα υπάρχει κάποια προτιμότερη (λιγότερο huh?!?!?!?).
 
Για μένα η ουσιαστική απάντηση είναι πως χρησιμοποιώντας array με τη λογική "το ίδιο πράγμα είναι" κάνεις μια τεράστια παράβλεψη που οφείλεται στο ότι δεν αναγνωρίζεις αρκετά στοιχεία στην έννοια "πράγμα" και αυτός είναι ο λόγος που τα βγάζεις ίδια. In other words, δεν αντιλαμβάνεσαι πως άλλο μπάλα ποδοσφαίρου και άλλο του βόλεϊ και λες που είναι το πρόβλημα, παίξτε με τη μπάλα του βόλεϊ.
 
Ποιά είναι η τεράστια διαφορά: με τον indexer δεσμεύεσαι όσον αφορά ένα μόνο μέρος του public interface. Με τον πίνακα δεσμεύεσαι στο σύνολο του public interface, και επιπλέον δεσμεύεσαι 100% και στην υλοποίηση.
 
Τι εννοώ.
 

interface IIndexable
{
    int this[int index] { get; }
}

interface IWhatever1
{
    IIndexable GetStuff();
}

interface IWhatever2
{
    int[] GetStuff();
}

Στον κώδικα που χρησιμοποιεί κάποιο Whatever, το ποιόν από τους δύο δρόμους θα πάρεις κάνει τεράστια διαφορά. Προφανώς όχι στη σύνταξη, γιατί εκεί η διαφορά είναι ακριβώς μηδέν. Η τεράστια διαφορά είναι στο τι υπόσχεται το εκάστοτε whatever σε αυτόν που θα καλέσει τη GetStuff(), και αγκαζέ μ' αυτό βέβαια πάνε και οι περιορισμοί τους οποίους επιβάλλει ο συγγραφέας του whatever στον εαυτό του.

 

Στην πρώτη περίπτωση η GetStuff υπόσχεται ότι θα πάρεις πίσω κάτι που του κάνεις index με int και σου δίνει πίσω πάλι int. Πέρα από αυτό δε σου υπόσχεται απολύτως τίποτα. Π.χ. αν ζητήσεις το [3], το indexing θα είναι O(1) ή κάτι άλλο; Who the fuck knows. Αν βάλεις ένα for και πάρεις όλα τα int με τη σειρά, το index στο [3] θα είναι το ίδιο γρήγορο με αυτό στο [4]? Who the fuck knows. Θα περίμενε κανείς να είναι, αλλά μη το δένεις και κόμπο. Αν κάνω δυο φορές GetStuff() στη σειρά θα πάρω πίσω το ίδιο type? Who knows. Αν κάνω μια φορά σήμερα και μιά μετά από 10 χρόνια στη backward-compatible version 123.0 της βιβλιοθήκης θα πάρω πίσω το ίδιο type? Δε νομίζω. Και ούτω καθεξής. 

 

Στη δεύτερη περίπτωση όμως η GetStuff έχει υποσχεθεί τα πάντα. Αυτό μπορεί να είναι καλό: ο caller ξέρει πάρα πολλά πράγματα για το πώς δουλεύουν τα arrays, και μπορεί να χρησιμοποιήσει όλη αυτή τη γνώση όπως νομίζει. Αλλά ταυτόχρονα είναι και κακό: ο συγγραφέας δε μπορεί πλέον να αλλάξει απολύτως τίποτα στα χαρακτηριστικά της επιστρεφόμενης τιμής χωρίς να σπάσει backward compatibility. Δηλαδή, άπαξ και πεις "επιστρέφω array", έχεις παντρευτεί το array για πάντα, και μαζί μ' αυτό και όλα του τα χούγια. Αν αποφασίσεις ότι χρειάζεται να αλλάξει οτιδήποτε είσαι υποχρεωμένος να σπάσεις το compatibility με όλο τον κώδικα που έχει γραφτεί για την class σου.

 

----

 

Τώρα που είπα αυτό που ήθελα για να μην εστιάσουμε σε "ασήμαντες λεπτομέρειες" και συγκεκριμένες υποπεριπτώσεις, ξαναγυρνάω λίγο στο πρακτικό. Έγραψα ότι θα παντρευτείς το array με όλα του τα χούγια. Αυτό μπορεί να μην είναι τόσο κακό. Έχει καλά χούγια το array: είναι γνώριμο, δεν έχει bugs, υποστηρίζεται από πάρα πολύ έτοιμο κώδικα, κλπ κλπ. Και το ότι θα παντρευτείς μπορεί να μη σε πειράζει. Στην τελική αν χρειαστεί ποτέ, δικό σου πρόγραμμα είναι, λογαριασμό δε δίνεις, παίρνεις μια βαθειά ανάσα και πάμε για αλλαγή. Και πιθανόν να μη χρειαστεί ποτέ. Οπότε βάζεις array, γιατί όχι; Και πραγματικά, αν κρίνεις από το πόσο συχνά συναντάς array και πόσο συχνά κάτι με indexer το πράγμα μιλάει από μόνο του. Είναι καλό το array.

 

Υπάρχουν όμως και περιπτώσεις όπου το array μας χαλάει το γλυκό, και αυτό που θα ήθελες θα ήταν ένα "σχεδόν array" αλλά όχι ακριβώς. Αυτός είναι ένας 100% χειροπιαστός πρακτικός λόγος να χρησιμοποιήσεις κάτι με indexer. Κλασικό παράδειγμα: φτιάξε μου ένα κάτι (sparse array λέγεται) που να μπορείς να το κάνεις index με int και θα περιέχει μέσα decimals. The catch: τα indexes πρέπει να φτάνουν μέχρι int.MaxValue, και δε σου λέω ποιά θα χρησιμοποιηθούν για διάβασμα/γράψιμο, αλλά να ξέρεις θα είναι το πολύ 100.

 

Καλή τύχη να κάνεις new decimal[int.MaxValue]. Ακόμα κι αν μπορούσες, κάνοντάς το θα δέσμευες 256GB μνήμης ενώ σου έχω πει από πριν ότι θα χρησιμοποιήσω γύρω στα 10KB. Με indexer όμως μπορείς. Και τι θα έχεις κάνει; Θα έχεις κρατήσει αυτό το μέρος του public interface ενός πίνακα που σου αρέσει, χωρίς να έχεις παντρευτεί τον τρόπο με τον οποίο υλοποιείται.

  • Like 5
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

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

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

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

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

Σύνδεση

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

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

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