C++ och dess framtid att programmera minnessäkert - Hur går utvecklingen?

Permalänk
Medlem
Skrivet av serafim:

Sökbar? Det är naturligtvis inte lätt för en enda person att utan hjälpmedel hålla reda på programkod oavsett storlek men med bra hjälpmedel, vettigt kommenterad kod, bra tester osv är det inga problem med en stor kodbas.

Läs det du skrev där igen och fundera på hur väl det stämmer. Är det inga problem med stor kodbas? Spelar mängden inte någon roll så länge den är väldokumenterad.
Hur hittar du i +1000 filer, är det inte svårare än om det är 10

Enligt mig går det inte att ta någon på allvar om den hystar ur sig sådant

Tvärtom så om man inte tänkt till ordentligt ökar problemen logaritimiskt, att dubbla mängden kan innbära bra mycket mer än dubbelt

Permalänk
Medlem
Skrivet av Yoshman:

Nu är Windows closed source, men de uppskattningar som finns på antal rader kernel-kod är långt mindre än dagens Linux-kärna.

Pratar du kärnan är den inte mindre eller så har linux rätt kass kod för att då har de producerat mycket kod för mindre funktionalitet.
Som vi konstaterat har Windows en hel del extra och släpa på, vissa saker är mycket bra men de har också annat som de nog ångrar

Permalänk
Medlem
Skrivet av klk:

Läs det du skrev där igen och fundera på hur väl det stämmer. Är det inga problem med stor kodbas? Spelar mängden inte någon roll så länge den är väldokumenterad.
Hur hittar du i +1000 filer, är det inte svårare än om det är 10

Enligt mig går det inte att ta någon på allvar om den hystar ur sig sådant

Tvärtom så om man inte tänkt till ordentligt ökar problemen logaritimiskt, att dubbla mängden kan innbära bra mycket mer än dubbelt

Återigen visar du att du svänger dig med uttryck som du inte begriper. Om något är logaritmiskt så betyder det att problemen minskar ju större koden blir. Det du antagligen är ute efter är exponentiell ökning (inversen av logaritmisk) men även där beror ökningshastigheten på basen, Är exponenten 2 kommer en ökning av kodbasen med 2 innebära att problemen (om vi utgår från att de finns) potentiellt ökar till 4 gånger flera.
Men det är ett underligt mått i samband med programkod, det används mest när man talar om komplexitet, framför allt när det gäller minneskomplexitet eller programkörtid, oftast i jämförelser mellan olika implementationer.

Det här börjar bli löjligt. För varje gång det visar sig att du har fel eller inte lyckas visa vad du menar så hittar du en annan vinkling för att fortsätta pladdret.

Korrigerade och rättade stavfel
Permalänk
Medlem
Skrivet av serafim:

Återigen visar du att du svänger dig med uttryck som du inte begriper. Om något är logaritmiskt så betyder det att problemen minskar ju större koden blir. Det du antagligen är ute efter är exponentiell ökning (inversen av logaritmisk) men även där beror ökningshastigheten på basen, Är exponenten 2 kommer en ökning av kodbasen med 2 innebära att problemen (om vi utgår från att de finns) potentiellt ökar till 4 gånger flera.

Sorry, jag skrev fel i hastigheten men jag tror du förstod vad jag menade

Skrivet av serafim:

Men det är ett underligt mått i samband med programkod, det används mest när man talar om komplexitet, framför allt när det gäller minneskomplexitet eller programkörtid, oftast i jämförelser mellan olika implementationer.

Det här börjar bli löjligt. För varje gång det visar sig att du har fel eller inte lyckas visa vad du menar så hittar du en annan vinkling för att fortsätta pladdret.

Gjorde en snabb beräknign på det ni arbtade och ni ligger på 1 person på drygt 6000 rader produktions kod. Du nämnde att ni var 25 i teamet, 360 000 rader kod varav 60% var testkod. Det är inte effektivt eller så har ni mycket svår domän.

10 000 rader produktionskod per år kan vilken programmerare som helst nå med bra teknik och det är en bra miljö och jobba i

Att det är "löjligt" eller någon anser att det är felaktig i ett område där det knappt existerar något rätt eller fel, vi jobbar med subjektivt område. Massor av projekt kraschar.

Det är vanligt att programmerare slår varandra i huvudet

Jag pratar om en teknik, den fungerar för en hel del. Vill man inte så skippa, personligen tycker jag alltid det är intressant om någon presenterar lösningar som kan göra något bättre.

Permalänk
Medlem
Skrivet av klk:

Pratar du kärnan är den inte mindre eller så har linux rätt kass kod för att då har de producerat mycket kod för mindre funktionalitet.
Som vi konstaterat har Windows en hel del extra och släpa på, vissa saker är mycket bra men de har också annat som de nog ångrar

Nej, Windowskärnan är programmerat i (en förenklad version) av C++ mens Linuxkärnan är programmerad i C med stort fokus på hastighet, vilket brukar betyda större kodbas. Men jag tror att @Yoshman har fel. Man tror att windows-11-kärnan är ungefär 50 000 000 rader kod mens Linux-kärnan (version 6.14) är drygt 40 000 000 rader kod. Sen kan jag ha fel eftersom senaste Linux-kärnan är 6.16.3 och storleken i rader kod för windows-11-kärnan är en gissning om än en hygglig sådan.

Permalänk
Medlem
Skrivet av serafim:

Nej, Windowskärnan är programmerat i (en förenklad version) av C++ mens Linuxkärnan är programmerad i C med stort fokus på hastighet, vilket brukar betyda större kodbas.

Det var mer än jag kände till, vet du när de bytte för den var från början kodad i C (windows alltså)

Permalänk
Medlem

@serafim @klk Flera referenser jag har hittat nämner uteslutande C och ASM för själva kärnan. Denna video av Raymond Chen förklarar det bäst.
https://learn.microsoft.com/en-us/shows/one-dev-minute/one-de...

Även David Delaune lutar åt det hållet även om han inte explicit nämner kärnan i sig. (Vilket för Windows del kan vara svår att avgränsa då det är så pass integrerat med UI.) Skrivet 2023.

Citat:

I worked on Windows 10, the majority of the operating system is written in C99. With a small amount written in C++. I don't think any part of the actual OS is using C#, maybe a few userland tools.

I do think there will be more Rust code added in Windows 11, it's all about that memory safety.

Sen angående sökning i stora kodbaser så bör väl koden struktureras upp och placeras i separata kataloger så att man redan från början har ett hum om var man skall börja leta. När jag dyker i linux-kärnan eller som just nu Firefox (ca 10 M rader kod, inkl kommentarer, exklusive include-filer, grovt räknat!) så finns det jag letar efter väl samlat i ett par delkataloger. Letar jag vidare efter procedurer eller variabler så stannar ju sökningarna inom dessa kataloger med hjälp av "grep | less".

Det som brukar hjälpa mig är att skapa en call-graph över applikationen, då får man en översikt över hur det hela hänger ihop.

klk: När du jobbar med HN är inte ägarskapet (ursprung) viktigare än typen? Jag skulle kunna tänka mig att om man har flera externa variabler (globaler) så kan man t.ex. namnge dem som eCustomer eller gCustomer. I mina småhack så namnger jag lokala procedurer som app_* och om de kommer från något externt bibliotek (bench.a) som bnc_* exempelvis. Aldrig någon tvekan om var jag hittar källkoden då.

Permalänk
Medlem
Skrivet av mc68000:

klk: När du jobbar med HN är inte ägarskapet (ursprung) viktigare än typen? Jag skulle kunna tänka mig att om man har flera externa variabler (globaler) så kan man t.ex. namnge dem som eCustomer eller gCustomer. I mina småhack så namnger jag lokala procedurer som app_* och om de kommer från något externt bibliotek (bench.a) som bnc_* exempelvis. Aldrig någon tvekan om var jag hittar källkoden då.

Ägarskapet är också viktigt men "min" lösning där är att skriva det efter variabeln. Ägarskapet är inte så viktigt för läshastighet (skanna kod) men däremot mycket viktigt för att förstå koden.

Tar jag ditt exempel så hade jag skrivit så här: customer_e eller customer_g om det är ett objekt som heter Customer.
Hade det varit static members i en klass, kanske static lokal variabel så kommer variabeln eller metoden avslutas med *_s. Det viktiga är inte att det just är ett s eller vad man nu väljer men att jag lätt kan se om det är en medlemsmetod eller en free function. Är det en free function vet jag att den inte påverkar något internt i objektet.

Ifall en variabel eller annat avslutas med _ använder jag det som att det kan vara precis vad som helst, att man måste granska koden. Smidigt när man gör små metoder där det bara är onödigt att kladda ner koden. Kanske överlagrade enrads-metoder mm

Min lilla styleguide (om jag får välja)

Dold text
Permalänk
Medlem
Skrivet av mc68000:

Sen angående sökning i stora kodbaser så bör väl koden struktureras upp och placeras i separata kataloger så att man redan från början har ett hum om var man skall börja leta. När jag dyker i linux-kärnan eller som just nu Firefox (ca 10 M rader kod, inkl kommentarer, exklusive include-filer, grovt räknat!) så finns det jag letar efter väl samlat i ett par delkataloger. Letar jag vidare efter procedurer eller variabler så stannar ju sökningarna inom dessa kataloger med hjälp av "grep | less".

Det är _också_ mycket viktigt. En sak där när jag pratat om repon och visat är det vanligt att inte alla har förståelse för att om man har som mål att koden skall kunna växa också behöver tänka på filstrukturen från början. Då kan man lätt åka på kritik för att det är onödigt komplicerat.

De som en gång tvingats jobba om filerna för att de placerats fel förstår däremot.
Har tvingats storstäda en gång, det tog tid

Permalänk
Datavetare
Skrivet av serafim:

All kod skrivs med ett syfte (hoppas jag) och ska naturligtvis vara användbar. Och bespara oss flera kodexempel, de ger ingenting. Man väljer datastrukturer och algoritmer efter vad som är tillgängligt i det valda språket så jämförelserna är onödiga och vad du vill uppnå med exemplen är obegripligt. Att Rust inte är objektorienterat är väl känt och vad jag vet är det främst i objektorienterade språk som överlagring existerar, har inte stött på det i andra typer av språk och t.ex. i Python som har ett klassbegrepp finns inte överlagring.

Det jag (vi?) gissar att "överlagring" refererar till här är polymorfism. Det är en viktigt komponent i OOP, men det är absolut inte bundet till OOP utan det är bara en komponent av många som används där. Clojure är inte alls OO, men där har man extremt flexibel modell för överlagring, går att göra på typ men även specifika värden för en typ.

Python har ju överlagring för klassmetoder precis som C++. Ovanpå det kan man ju använda "duck-typing" där, lite likt hur man kan göra statisk överlagring i C++ via template men skillnaden att i Python blir det ett runtime-fel om metoden man anropar inte finns på typen medan det i C++ blir ett kompileringfel. Både Rust och Go kan göra motsvarande (och en rad andra språk också).

C++ vtable struct Animal { virtual ~Animal() = default; virtual void makeSound() const = 0; }; struct Dog : Animal { void makeSound() const override { std::cout << "woff\n"; } }; struct Duck : Animal { void makeSound() const override { std::cout << "quack\n"; } }; int main() { std::vector<std::unique_ptr<Animal>> zoo; zoo.emplace_back(std::make_unique<Dog>()); zoo.emplace_back(std::make_unique<Duck>()); for (auto& a : zoo) a->makeSound(); } C++ templates struct Dog { void makeSound() const { std::cout << "woff\n"; } }; struct Duck { void makeSound() const { std::cout << "quack\n"; } }; template <class T> void speak(const T& t) { t.makeSound(); } // requires T has makeSound() int main() { Dog d; Duck k; speak(d); speak(k); } Rust traits trait Animal { fn make_sound(&self); } struct Dog; struct Duck; impl Animal for Dog { fn make_sound(&self) { println!("woff"); } } impl Animal for Duck { fn make_sound(&self) { println!("quack"); } } fn main() { let zoo: Vec<Box<dyn Animal>> = vec![Box::new(Dog), Box::new(Duck)]; for a in &zoo { a.make_sound(); } } Rust generics trait Animal { fn make_sound(&self); } struct Dog; struct Duck; impl Animal for Dog { fn make_sound(&self) { println!("woff"); } } impl Animal for Duck { fn make_sound(&self) { println!("quack"); } } fn speak<T: Animal>(t: &T) { t.make_sound(); } fn main() { let d = Dog; let k = Duck; speak(&d); speak(&k); } Go interface type Animal interface { MakeSound() } type Dog struct{} type Duck struct{} func (Dog) MakeSound() { fmt.Println("woff") } func (Duck) MakeSound() { fmt.Println("quack") } func main() { zoo := []Animal{Dog{}, Duck{}} for _, a := range zoo { a.MakeSound() } } Go "static" style type Speaker interface { MakeSound() } type Dog struct{} type Duck struct{} func (Dog) MakeSound() { fmt.Println("woff") } func (Duck) MakeSound() { fmt.Println("quack") } func Speak[T Speaker](t T) { t.MakeSound() } func main() { Speak(Dog{}) Speak(Duck{}) } Python class Animal: def make_sound(self): # "virtual" method raise NotImplementedError("Subclass must implement make_sound()") class Dog(Animal): def make_sound(self): print("woff") class Duck(Animal): def make_sound(self): print("quack") zoo: list[Animal] = [Dog(), Duck()] for animal in zoo: animal.make_sound() # Calls the appropriate override

trivial exempel med överlagring i C++, Rust, Go och Python
Skrivet av serafim:

Nej, Windowskärnan är programmerat i (en förenklad version) av C++ mens Linuxkärnan är programmerad i C med stort fokus på hastighet, vilket brukar betyda större kodbas. Men jag tror att @Yoshman har fel. Man tror att windows-11-kärnan är ungefär 50 000 000 rader kod mens Linux-kärnan (version 6.14) är drygt 40 000 000 rader kod. Sen kan jag ha fel eftersom senaste Linux-kärnan är 6.16.3 och storleken i rader kod för windows-11-kärnan är en gissning om än en hygglig sådan.

Som sagt, svårt att säga exakt givet att Windows är closed-source. Men givet din 50M siffra tror jag du hittat samma referens som jag gjorde. Notera att 50M är totala mängden SLOC för ett komplett Windows 10 server OS, d.v.s. både kernel och det userland som är inkluderat. Koden för kärnan är en rätt liten del av det.

Linux är en kärna, Ubuntu är ett Linux-baserat OS så är i så fall det senare man skulle jämföra med (i en grundläggande installation).

Det vore högst märkligt om Windows-kärnan som den ser ut hos Microsoft skulle ha fler SLOC än Linux givet att en förkrossande majoritet av koden i Linux är drivers. Windows har drivers för en del grundläggande saker, men majoriteten av drivers kommer där i binärform från 3:e-part.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av Yoshman:

Det vore högst märkligt om Windows-kärnan som den ser ut hos Microsoft skulle ha fler SLOC än Linux givet att en förkrossande majoritet av koden i Linux är drivers. Windows har drivers för en del grundläggande saker, men majoriteten av drivers kommer där i binärform från 3:e-part.

Kände inte till att man räknade koden för drivarna i linux, det förklarar varför linux uppfattas som lika stort. Blir lite som att jämföra äpplen och päron

Permalänk
Datavetare
Skrivet av klk:

Kände inte till att man räknade koden för drivarna i linux, det förklarar varför linux uppfattas som lika stort. Blir lite som att jämföra äpplen och päron

En OS-kärna består typiskt av relativt lite kod. Dels är det inte supermånga funktioner man har i en OS-kärna, grovt är 1/3-del schemaläggning, interrupt-hantering, systemanrop etc (i.e. core-core), 1/3-del är filsystemhantering och 1/3 del nätverksstacken.

Majoriteten av OS-kod är systembibliotek och systemtjänster, alla ligger i user-land om man inte har en totalt idiotisk design alt. det är ett embedded-OS där allt ligger i samma adressrymd.

"Korkade" saker i Windows som registret och liknande ligger inte i kärnan. Vidare är Windows-kärnan en hybridkärna, så den har i alla fall potential att ha mindre delar i kernel-space än en traditionell monolitisk kärna som Linux (tror Windows sedan länge har ljud, USB och lite mer out-of-kernel).

Sen består även vissa drivers allt mer av user-land kod. En modern GPU-driver har väldigt lite av koden körandes i kärnan, alla avancerade funktioner ligger numera i user-land. Det är förklaringen till varför saker som PyTorch med CUDA-acceleration presterar i stort sett lika bra under WSL2 som under "native" Linux. Att Linux kan vara upp till dubbelt så snabb här kommer av skillnader i user-land, WSL2 använder Windows-drivers för kernel-delen och Linux-drivers för user-land delen.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Skrivet av klk:

Har du regler så alla utvecklare skriver samma typ av kod kommer också alla utvecklare veta hur de söker i annans kod. De vet vad det skall söka efter. En regel för hur variabler och annat benämns gör det enklare för hela teamet.
Om man tvärtom får namnge saker till vad man känner för så lycka till med att söka efter saker, instanser av olika objekt kan ha många olika namn. metoder och annat kan också följa olika mönster. Lägg på dessäng problem, metoder som gör flera saker, kanske objekt där "här slänger vi in det här också". det går fort att förstöra kod

HN är ett "mönster" och desto mer komplicerad kod eller desto mer den växer desto viktigare blir sådant här. HN är inte det enda för att hantera stora kodmängder utan de måste ta till alla möjliga trick för att klara av och hantera koden.

Jag vill backa diskussionen till HN igen. Jag förstår inte varför du envisas med att ställa HN och strikta regler för namngivning mot kaoset som uppstår när "man ... får namnge saker till vad man känner för". Även inom HN finns det en del av namnet, mellan prefix och eventuellt suffix som skall förmedla intent. Det styrs väl inte av HN utan utvecklaren kan välja själv här? Om någon av dina kollegor skulle få för sig att plocka slumpvisa ord ur ordlistan, säg gurka, volvo, sjöstjärna, hur mycket är du då behjälpt av att de i HN istället heter pGurka, uVolvo eller dSjöstjärna?

Är det så i din föreställningsvärld, att team som inte kör HN enkom består av ett gäng med sopprötter som medvetet kommer välja namn som gurka, volvo, och sjöstjärna för sina vektorer med kunddata, prislistor och filpekare? Och dessutom ta ett annat namn i nästa funktion? Varför skulle det automatiskt bli rörig namngivning bara för att man inte kör HN?

Lek med tanken att även medelbegåvade utvecklare väljer variabelnamn så de sammanfaller med den terminologi som gäller för domänen de jobbar med. Teamet har dessutom regler för hur namngivningen skall göras (style guide?), vad som ska förkortas och vad som inte ska förkortas, vilka standardavsteg som finns från namngivning, typ att loopvariabler får heta i, j, k, och att folk följer den etablerade stilen i projektet. Då ser jag inga som helst fördelar med HN. På vilket blir det bättre av att variabeln heter pSomething istället för something? Ja, du kan redan i sökningen skilja på pekare till something och vektorer eller listor av something, men det är väl ändå something som är det väsentliga och det du kommer söka på om du letar efter kod som hanterar something (ersätt something med en etablerad term som förekommer i er kod)?

Jag vet redan att du tycker HN är bättre och att du tycker att det blir lättare att hantera och söka i stora projekt, så det behöver du inte berätta en gång till. Jag är nyfiken på vad som gör det bättre, vad ser du för konkreta fördelar gentemot att inte ha typprefix på variablerna? Hur blir du hjälpt? I vilka fall blir det mycket bättre med HN?

Permalänk
Medlem
Skrivet av Yoshman:

Det jag (vi?) gissar att "överlagring" refererar till här är polymorfism. Det är en viktigt komponent i OOP, men det är absolut inte bundet till OOP utan det är bara en komponent av många som används där. Clojure är inte alls OO, men där har man extremt flexibel modell för överlagring, går att göra på typ men även specifika värden för en typ.

Python har ju överlagring för klassmetoder precis som C++. Ovanpå det kan man ju använda "duck-typing" där, lite likt hur man kan göra statisk överlagring i C++ via template men skillnaden att i Python blir det ett runtime-fel om metoden man anropar inte finns på typen medan det i C++ blir ett kompileringfel. Både Rust och Go kan göra motsvarande (och en rad andra språk också).

C++ vtable struct Animal { virtual ~Animal() = default; virtual void makeSound() const = 0; }; struct Dog : Animal { void makeSound() const override { std::cout << "woff\n"; } }; struct Duck : Animal { void makeSound() const override { std::cout << "quack\n"; } }; int main() { std::vector<std::unique_ptr<Animal>> zoo; zoo.emplace_back(std::make_unique<Dog>()); zoo.emplace_back(std::make_unique<Duck>()); for (auto& a : zoo) a->makeSound(); } C++ templates struct Dog { void makeSound() const { std::cout << "woff\n"; } }; struct Duck { void makeSound() const { std::cout << "quack\n"; } }; template <class T> void speak(const T& t) { t.makeSound(); } // requires T has makeSound() int main() { Dog d; Duck k; speak(d); speak(k); } Rust traits trait Animal { fn make_sound(&self); } struct Dog; struct Duck; impl Animal for Dog { fn make_sound(&self) { println!("woff"); } } impl Animal for Duck { fn make_sound(&self) { println!("quack"); } } fn main() { let zoo: Vec<Box<dyn Animal>> = vec![Box::new(Dog), Box::new(Duck)]; for a in &zoo { a.make_sound(); } } Rust generics trait Animal { fn make_sound(&self); } struct Dog; struct Duck; impl Animal for Dog { fn make_sound(&self) { println!("woff"); } } impl Animal for Duck { fn make_sound(&self) { println!("quack"); } } fn speak<T: Animal>(t: &T) { t.make_sound(); } fn main() { let d = Dog; let k = Duck; speak(&d); speak(&k); } Go interface type Animal interface { MakeSound() } type Dog struct{} type Duck struct{} func (Dog) MakeSound() { fmt.Println("woff") } func (Duck) MakeSound() { fmt.Println("quack") } func main() { zoo := []Animal{Dog{}, Duck{}} for _, a := range zoo { a.MakeSound() } } Go "static" style type Speaker interface { MakeSound() } type Dog struct{} type Duck struct{} func (Dog) MakeSound() { fmt.Println("woff") } func (Duck) MakeSound() { fmt.Println("quack") } func Speak[T Speaker](t T) { t.MakeSound() } func main() { Speak(Dog{}) Speak(Duck{}) } Python class Animal: def make_sound(self): # "virtual" method raise NotImplementedError("Subclass must implement make_sound()") class Dog(Animal): def make_sound(self): print("woff") class Duck(Animal): def make_sound(self): print("quack") zoo: list[Animal] = [Dog(), Duck()] for animal in zoo: animal.make_sound() # Calls the appropriate override

trivial exempel med överlagring i C++, Rust, Go och Python

[...]

Jag skulle hävda att detta är exempel på "överskuggning" (eng. overriding), dvs då en subtyp omdefinierar en metod definierad av en supertyp.

När det kommer till "överlagring" (eng. overloading) så handlar det om att ge samma namn till olika operationer, och det har inte nödvändigtvis någonting med typhierarkier att göra alls. Vad som händer är kontextuellt, där kontexten i sig kan te sig på olika sätt. Ett praktexempel är att det är funktionsargumenten som ger kontexten, ex. genom att ha olika mängd argument eller olika typer på argumenten (se exempel i Java nedan).

public class Adder { public static void main(String[] args) { System.out.println(add(1, 2)); // 3 System.out.println(add(1, 2, 3)); // 6 System.out.println(add("1", "2")); // "3" } public static int add(int lhs, int rhs) { return lhs + rhs; } public static int add(int a, int b, int c) { return a + b + c; } public static String add(String lhs, String rhs) { return String.valueOf((Integer.parseInt(lhs) + Integer.parseInt(rhs))); } }

Dold text

Min uppfattning är att dessa definitioner är vedertagna, och stöds även av Wikipedia-artiklarna på overloading och overriding. Jag lärde ut detta i många år på KTH och det fanns en konsensus inom fakulteten att detta är hur dessa ord ska användas.

Det är dock möjligt att de svenska termerna är lite mer flytande, vi har minst sagt haft lite problem med terminologi i svenskan vad gäller programmering.

Hur mycket tillför detta till nuvarande snurr i denna tråd? Oklart. Antagligen ingenting. Men jag kände ett behov av att förtydliga dessa ofta ihopblandade termer.

Permalänk
Medlem
Skrivet av SimpLar:

...
När det kommer till "överlagring" (eng. overloading) så handlar det om att ge samma namn till olika operationer, och det har inte nödvändigtvis någonting med typhierarkier att göra alls.
...

Jag håller med jag tolkar överlagring som overloading som i function overloading. Det hjälper dock inte diskussionen om vad @klk egentligen menar eftersom jag redan frågat @klk om det är funtion overloading som han syftar på när han säger "överlagring".

Skrivet av orp:

...
Är det overloading du syftar på med överlagring som i function overloading?

Här frågar jag och fick följande som svar...

Skrivet av klk:

Så här. Etablerade termer och annat är ofta anpassade så att så många som möjligt skall förstå, kan man inte göra sig förstådd på typ 10 minuter så är det bara att glömma och beskriva något online (finns så gott om "experter") som vet bättre.. Och de är snabba och beskriva vad som är bäst (enligt dem).

Det går inte att ha tekniska diskussioner när det blir invecklat

Angående överlagring så tänk på en telefonbok, hur kommer det sig att man klarar av och hitta och läsa en telefonbok trots tusentals sidor, spelar ingen roll och man ökar på antalet sidor, det går lika snabbt ändå

Samma sak med kod, vi människor är begränsade i hur mycket vi kan ha i huvudet samtidigt och hur mycket vi kommer ihåg. Och vad en person kommer ihåg, det vet inte en annan.

Möjligen finns någon supermänniska som kan minnas hur mycket som helst men den har inte jag sett så tills dess går det faktiskt att se ganska snabbt på kod hur långt de kan komma.
Det är också därför jag sagt några gånger i tråden att viss teknik har svårt att skala, granskar man koden så kan man snabbt se hur långt de kommer komma även om det är mycket duktiga utvecklare. Har de inte tänkt på vår hjärnas begränsning i vad som går att minnas och ha kontroll över så kommer det inte så långt innan det börjar gå vääääääääääääldigt trögt.
Och när utvecklare får lägga så mycket energi på att bara komma ihåg saker så blir det tråkigt, det tar mental kraft som förstör arbetsglädjen

Permalänk
Medlem
Skrivet av orp:

Jag håller med jag tolkar överlagring som overloading som i function overloading. Det hjälper dock inte diskussionen om vad @klk egentligen menar eftersom jag redan frågat @klk om det är funtion overloading som han syftar på när han säger "överlagring".

Här frågar jag och fick följande som svar...

Överlagring kan användas till mycket, långt mer än OOP
https://en.wikipedia.org/wiki/Function_overloading

Permalänk
Medlem
Skrivet av klk:

Överlagring kan användas till mycket, långt mer än OOP
https://en.wikipedia.org/wiki/Function_overloading

Jag har aldrig sagt något om OOP utan har frågat dig om det är function overloading utan att få något svar. Jag har t o m uppmuntrat dig att läsa Wiki-sidan istället ger du osammanhängande förklaringar som är långt ifrån function overloading som telefonkatalogsexemplet.

Skrivet av orp:

...
Problemet är inte att saker är invecklade. Istället för att du går till Wiki-sidan för att kontrollera om "function overloading" är samma som du hade i åtanke och svara "ja, det är det jag tänkte på" eller "nej, jag tänkte på något annat" så får vi otekniska berättelser som nedan.
...

Det var samma inlägg som jag sa att ditt telefonkatalogsexempel inte beskriver functional overloading... Trots det försökte du dig på att dra samma exempel mot @Yoshman en andra gång istället för att ge en teknisk förklaring på vad du egentligen menar ...

Skrivet av klk:

Repeterar
Om du får en telefonbok med tusentals sidor, spelar det någon roll för hur snabbt du hittar i telefonboken?
Om du får en tjock skönlitterär bok på tusen sidor, hur snabbt hittar du i den?

Är du med?

Permalänk
Medlem
Skrivet av klk:

Det var mer än jag kände till, vet du när de bytte för den var från början kodad i C (windows alltså)

Visar sig att jag har fel, kärnan är tydligen skriven i C och det mesta av senare tillägg (som inte räknas till själva kärnan) är skrivet i C++, så fel av mig. Då blir det lite av en gissning vad som gör den ena större än den andra och jag skulle inte vilja räkna rader kod (som jag redan sagt är ett uddlöst sätt att räkna givet alla olika idéer om hur kod ska skrivas), enkelt exempel:

int main(void) { printf("Hello World!\n"); return 0; }

jämfört med

int main(void) { printf("Hello World!\n"); return 0; }

jämfört med

int main(void) { printf("Hello World!\n"); return 0; }

Som när man räknar rader kod ger 1, 4 och 5 för exemplen.
Det är bättre (enligt min mening) att mäta storleken på den kompilerade koden som med optimerande kompilator skulle ge samma storlek för alla tre exemplen ovan. Men nu mäter man kodrader i Linux och gissar avseende Windows.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Jag vill backa diskussionen till HN igen. Jag förstår inte varför du envisas med att ställa HN och strikta regler för namngivning mot kaoset som uppstår när "man ... får namnge saker till vad man känner för". Även inom HN finns det en del av namnet, mellan prefix och eventuellt suffix som skall förmedla intent. Det styrs väl inte av HN utan utvecklaren kan välja själv här? Om någon av dina kollegor skulle få för sig att plocka slumpvisa ord ur ordlistan, säg gurka, volvo, sjöstjärna, hur mycket är du då behjälpt av att de i HN istället heter pGurka, uVolvo eller dSjöstjärna?

Stämmer, HN har två delar, en som är flexibel och en som är fast. Den fasta används för att skanna koden och den flexibla för att se mer detaljerat. Den fasta är också mycket användbar för att snabbt känna igen vad som är viktigt att titta på. HN passar också för de utvecklare som gärna använder "auto,let" och liknande för att deklarera variabler
Har du inget likt HN och deklererar med "auto, let, var" så blir koden mycket svårare att läsa.

Skrivet av Ingetledigtnamn:

Är det så i din föreställningsvärld, att team som inte kör HN enkom består av ett gäng med sopprötter som medvetet kommer välja namn som gurka, volvo, och sjöstjärna för sina vektorer med kunddata, prislistor och filpekare? Och dessutom ta ett annat namn i nästa funktion? Varför skulle det automatiskt bli rörig namngivning bara för att man inte kör HN?

Om du inte väljer HN untyttjar man inte möjligheter att göra koden mer förståelig för utvecklare, exempelvis för domäner som är väldigt svåra. Där kan i princip inte utvecklare jobba med koden utan att gå någon kurs eller liknande för att lära sig vad olika namn är för något, även om de gör det blir det mycket svårt att jobba i koden.

HN är också smidigt för att göra koden sökbar, kunna första komplex kod, stora metoder mm. Utvecklare slipper ödsla så mycket energi på att minnas och utvecklaren behöver heller inte hovra eller backa till deklaration för att friska upp minnet vad det var.

Och det viktigaste av allt som man ofta glömmer, men då tänker jag mer på att börja alla instanser av objekt som inte har förkortningar med hela klassnamnet i små bokstäver. För om man gör det så kommer programmeraren att lära sig koden/objekten medan man försöker förstå koden. Att skriva program är ibland som att hitta på ett nytt språk. Alla objektnamn mm är ju ord eller sekvenser av ord som betyder något.

Skrivet av Ingetledigtnamn:

Lek med tanken att även medelbegåvade utvecklare väljer variabelnamn så de sammanfaller med den terminologi som gäller för domänen de jobbar med. Teamet har dessutom regler för hur namngivningen skall göras (style guide?), vad som ska förkortas och vad som inte ska förkortas, vilka standardavsteg som finns från namngivning, typ att loopvariabler får heta i, j, k, och att folk följer den etablerade stilen i projektet. Då ser jag inga som helst fördelar med HN.

Se det jag räknade upp men givetvis är det också bra om alla utvecklare kan domänen, problemet är bara att samma sak kommer få så många olika namn så även om de kan domänen blir det slarvigare.

Enligt mig så det absolut största motståndet mot HN är att utvecklare är själviska, man vill inte anpassa sig utan skriva kod som man själv brukar skriva. Och att undvika det "krig" som kommer uppstå när själviska personer skall anpassa sig.
Att lyckas införa det här i stort företag som microsoft är en prestation men att de ändå lyckades var att den typen av kod de skulle göra var nära nog omöjlig att klara av om de inte använt HN.

Vet att flera inte tror det men om projektet är komplicerat är sådant här i princip en nödvändighet för att lyckas.

Permalänk
Medlem

@klk

Vidare gällande functional overloading...

Om du hade beskrivit det i stil med "att deklarera samma funktion med olika parametrar" istället för:

Skrivet av klk:

Angående överlagring så tänk på en telefonbok, hur kommer det sig att man klarar av och hitta och läsa en telefonbok trots tusentals sidor, spelar ingen roll och man ökar på antalet sidor, det går lika snabbt ändå

Då hade nog alla varit med på vad du menar ...

Permalänk
Medlem
Skrivet av orp:

@klk

Vidare gällande functional overloading...

Om du hade beskrivit det i stil med "att deklarera samma funktion med olika parametrar" istället för:

Då hade nog alla varit med på vad du menar ...

Om du visste vad svårt det är att veta hur man bäst beskriver något i text. Mycket enklare live

Men jag tror inte så många utvecklare är vana vid att ha det fokus på att skriva koden i mönster, får jag välja så och någon annan skulle se hur mycket jag anstränger mig för att allt skall se likt ut tror jag de tycker jag är konstig (i början).
Kan gå extremt långt för att få till det

Nämner att det också blir problem om någon chef vill få in en funktionalitet, då kan jag säga nej även om det är lätt att hacka in lösningen. Hack är enligt mig också något som är nära nog förbjudet

Permalänk
Medlem
Skrivet av serafim:

Då blir det lite av en gissning vad som gör den ena större än den andra och jag skulle inte vilja räkna rader kod (som jag redan sagt är ett uddlöst sätt att räkna givet alla olika idéer om hur kod ska skrivas), enkelt exempel:

Absolut är det ett mycket trubbigt mått men det är ändå något för att bilda sig en uppfattning.
Personligen kan jag försöka använda rätt mycket i bredd och även "gömma kod" långt ut till höger och det kan skilja en hel del i antal rader jämfört med någon som eventuellt har en maxgräns på 80 tecken

Det lilla sökprogram jag gjort kan räkna programmeringstecken, och det är ibland intressant och se hur olika typer av kod skiljer. Men det spelar då också roll för hur långa namnen är, exempelvis språk med fokus på objektorienterade lösningar brukar ha mycket långa namn

Permalänk
Medlem
Skrivet av klk:

Om du visste vad svårt det är att veta hur man bäst beskriver något i text. Mycket enklare live

Alltså ... du använde termen överlagring på ett sätt som inte passade sammanhanget. Jag kontrollfrågade vad du menar med överlagring och frågade om det var functional overloading. Vid detta tillfället kunder du bara googlat och sagt ja/nej eller gett ett kodexempel. Istället så säger du det med telefonkatalogen som inte har något att göra med något vi pratat om ...

Man behöver ju inte vara någon Shakespeare för att skriva ja/nej eller posta ett relevant kodexempel.

Skrivet av klk:

Men jag tror inte så många utvecklare är vana vid att ha det fokus på att skriva koden i mönster, får jag välja så och någon annan skulle se hur mycket jag anstränger mig för att allt skall se likt ut tror jag de tycker jag är konstig (i början).
Kan gå extremt långt för att få till det

Nu förstår jag inte vad du menar igen. Hur gick vi från overloading till mönster?

All kod är någon form av mönster, så utvecklare är definitivt vana vid att koda i mönster som skapas av uppgifterna vi löser och språkkonstruktionerna vi använder.

Skrivet av klk:

Nämner att det också blir problem om någon chef vill få in en funktionalitet, då kan jag säga nej även om det är lätt att hacka in lösningen. Hack är enligt mig också något som är nära nog förbjudet

Nu förstår jag inte vad du menar igen. Hur gick vi från overloading till mönster till vad chefen tycker till vad du anser om hack?

Permalänk
Medlem
Skrivet av SimpLar:

Jag skulle hävda att detta är exempel på "överskuggning" (eng. overriding), dvs då en subtyp omdefinierar en metod definierad av en supertyp.

När det kommer till "överlagring" (eng. overloading) så handlar det om att ge samma namn till olika operationer, och det har inte nödvändigtvis någonting med typhierarkier att göra alls. Vad som händer är kontextuellt, där kontexten i sig kan te sig på olika sätt.

Tack, bra förklarat

Ibland råkar så kallade "gud" objekt uppstå i kod, objekt som kan "allt". Kod som är svår att refakorera men funktionalitet måste in eller att man inte vet den perfekta designen.
Utan att kunna överlagra är det löjligt svårt att ha kontroll.

En sak jag inte begripit med rust och deras vilja att skriva om befintliga lösningar gjorda i C eller C++ i rust kanske har med det här och göra. Skall något göras i rust tolkar jag det som att man nära nog måste veta designen innan man kodar in det. Språket är så reglerat att det blir svårt att slarva. Och kanske det är därför de gärna skriver om istället för att hitta på nytt, då är redan designen där.
För skall man skriva något nytt så vet man sällan vad det färdiga resultatet kommer bli, man måste kunna mixa/leka fram lösningar och testa olika varianter. Då underlättar det massor om man kan överlagra

Permalänk
Medlem
Skrivet av orp:

Nu förstår jag inte vad du menar igen. Hur gick vi från overloading till mönster till vad chefen tycker till vad du anser om hack?

Hack = stämmer inte med designen, skiljer från mönstret, plåster (vad finns mer att likna de vid)

Om du råkar få ett sår, kanske i armen, använder plåster för att det inte skall blöda. Då ser du att plåstret skiljer från mönstret och ditt mönster på armen är hud. Ett plåster är inte hud

Permalänk
Medlem
Skrivet av klk:

En sak jag inte begripit med rust och deras vilja att skriva om befintliga lösningar gjorda i C eller C++ i rust kanske har med det här och göra. Skall något göras i rust tolkar jag det som att man nära nog måste veta designen innan man kodar in det. Språket är så reglerat att det blir svårt att slarva. Och kanske det är därför de gärna skriver om istället för att hitta på nytt, då är redan designen där.
För skall man skriva något nytt så vet man sällan vad det färdiga resultatet kommer bli, man måste kunna mixa/leka fram lösningar och testa olika varianter. Då underlättar det massor om man kan överlagra

Jag har inte upplevt sådana problem. Källkoden blir inte read-only efter att man skrivit den till disk, det är bara att uppdatera den.
Jag har aldrig sett det som du beskriver som ett problem pga avsaknat stöd för överlagring. Varför inte skapa ett generiska funktioner eller generiska interface olika metoder eller vad om helst, det finns mängder med alternativ?

Permalänk
Datavetare
Skrivet av SimpLar:

Jag skulle hävda att detta är exempel på "överskuggning" (eng. overriding), dvs då en subtyp omdefinierar en metod definierad av en supertyp.

"override" är för mig specifikt fallet där en subtyp definierar om / lägger till till något som redan är definierat av en supertyp.

Men det är långt ifrån alla varianter av runtime-polymorfism och för mig sin ganska sällan använder OOP är det en rätt ovanlig användning.

Dynamisk polymorfism är ju oftast bara att olika typer (och potentiellt olika andra selektorer, t.ex. värde i Clojure) avgör hur en viss metod hanteras.

Skrivet av SimpLar:

När det kommer till "överlagring" (eng. overloading) så handlar det om att ge samma namn till olika operationer, och det har inte nödvändigtvis någonting med typhierarkier att göra alls. Vad som händer är kontextuellt, där kontexten i sig kan te sig på olika sätt. Ett praktexempel är att det är funktionsargumenten som ger kontexten, ex. genom att ha olika mängd argument eller olika typer på argumenten (se exempel i Java nedan).

public class Adder { public static void main(String[] args) { System.out.println(add(1, 2)); // 3 System.out.println(add(1, 2, 3)); // 6 System.out.println(add("1", "2")); // "3" } public static int add(int lhs, int rhs) { return lhs + rhs; } public static int add(int a, int b, int c) { return a + b + c; } public static String add(String lhs, String rhs) { return String.valueOf((Integer.parseInt(lhs) + Integer.parseInt(rhs))); } }

Dold text

Det är en form av överlagring. Just ditt exempel hade lika väl kunna hanteras med en variadic funktion och då hantera godtyckligt antal argument av en viss typ.

Den här typen av polymorfism verkar inte gillas av alla. Vissa moderna språk, som t.ex. Go och Rust väljer ju att INTE stödja detta.

Sen är inte heller detta den enda formen av compile-time polymorfism. C++ templates gör ju sådana val compile-time (Rust har liknade funktionalitet)

Så att bara säga "överlagra" är inte i närheten tillräckligt exakt för att man ska förstå vad som menas!

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av klk:

Gjorde en snabb beräknign på det ni arbtade och ni ligger på 1 person på drygt 6000 rader produktions kod. Du nämnde att ni var 25 i teamet, 360 000 rader kod varav 60% var testkod. Det är inte effektivt eller så har ni mycket svår domän.

Ett team består inte bara av programmerare, en del är interaktionsdesigners (som absolut inte ska skriva kod, de är ofta ganska kassa på det, i alla fall är det min erfarenhet), andra är systemarkitekter (som inte heller ska koda), minst en har till uppgift att samordna övrigas verksamhet och sen har vi programmerarna (som inte ska göra annat än koda och dokumentera koden, absolut inte lägga sig i designers och arkitekters jobb).
Det är min erfarenhet men det finns naturligtvis de som kan ha gränsöverskridande verksamhet. Ta mina kommentarer inom parenteser med ett par nypor salt

Permalänk
Medlem
Skrivet av Yoshman:

Det är en form av överlagring. Just ditt exempel hade lika väl kunna hanteras med en variadic funktion och då hantera godtyckligt antal argument av en viss typ.

Då får du inte kompilatorkontroll, utvecklaren måste skriva felhantering i metoden för felaktiga argument och koden är svårare att läsa.

Båda tekniker är användbara men i olika sammanhang.

Skrivet av Yoshman:

Den här typen av polymorfism verkar inte gillas av alla. Vissa moderna språk, som t.ex. Go och Rust väljer ju att INTE stödja detta.

Det beror på att Åsa Nisse kan göra fel, att det är en tröskel och de vill inte ha den typen av trösklar.

Flexibilitet kräver ansvar

Permalänk
Medlem
Skrivet av Yoshman:

"override" är för mig specifikt fallet där en subtyp definierar om / lägger till till något som redan är definierat av en supertyp.

Det är exakt vad Python-koden i ditt exempel gör, och jag erkänner att jag stirrade mig lite blind på just den delen. Jag medger att det pattern som används härmar interfaces i andra språk, men Python's runtime saknar interfaces och detta är i praktiken överskuggning sett till hur iaf CPython kommer utvärdera anrop till metoden.

Skrivet av Yoshman:

Men det är långt ifrån alla varianter av runtime-polymorfism och för mig sin ganska sällan använder OOP är det en rätt ovanlig användning.

Vi kanske talar om varandra. Jag tolkade som att du i ditt inlägg menade att alla exempel demonstrerade överlagring eftersom spoilern löd "trivial exempel med överlagring i C++, Rust, Go och Python", men baserat på detta uttalande kanske du helt enkelt bara demonstrerade polymorfism? Det har jag inga invändningar mot, det är absolut polymorfism alltihop.

Jag är heller inte av uppfattningen att implementering av interfaces/traits är något som generellt definieras som överlagring. Om vi tar Go som exempel har till och med dess FAQ en sektion som talar om varför språket inte stödjer överlagring. Polymorfism? Absolut. Men överlagring? Det har jag svårt att se att många skulle tolka det som, även om jag till viss del håller med om att det skulle kunna passa in rent definitionsmässigt ("kontexten" för överlagringen blir den konkreta typen).

Skrivet av Yoshman:

Det är en form av överlagring. Just ditt exempel hade lika väl kunna hanteras med en variadic funktion och då hantera godtyckligt antal argument av en viss typ.

Jag tror att du missade den sista metoden som tar strängar istället för ints. Det går inte generellt att hantera med variadics. Och även om det skulle gå hävdar jag ändå att detta är typexempel på (funktions/metod)överlagring. Att andra tekniker kan uppnå samma sak (generics, till exempel) gör inte att detta blir mindre överlagrat.

Den andra välkända formen av överlagring är operatoröverlagring, som om något är ännu mer omtvistat än funktionsöverlagring. Men principen är exakt densamma.

Skrivet av Yoshman:

Så att bara säga "överlagra" är inte i närheten tillräckligt exakt för att man ska förstå vad som menas!

Innan denna diskussion skulle jag säga att det är fullt tillräckligt! Att bara säga "överlagra" är i min mening starkt indikativt att personen avser funktions- eller operatoröverlagring, givet att denne har ett hyggligt grepp om programmering, och kontexten borde avslöja resten. Men då jag anser att du är en högst påläst och kunnig person så får jag helt enkelt medge att det inte är tillräckligt, denna diskussion är ju inget annat än skriftligt bevis för det. Iallafall inte när kontexten är såpass lösryckt som den är här.

Nu har jag nog gjort mitt i att gå på side quests i denna tråd. Jag tror vi eventuellt får "agree to disagree".