Libreria / Runtime API tra versioni

6

Stavo conversando con un amico sulla classe diStringBuilder C #%, e qual era il suo comportamento. Parafrasando, ma il mio lato della conversazione è stato qualcosa di simile (ho semplificato eccessivamente perché esattamente come StringBuilder funziona non è importante per la mia domanda)

StringBuilder is more efficient to use for extensive string concatenation than to simply use +. The reason is that StringBuilder doesn't dynamically create a new string for each concatenation operation. It waits until all of your desired concatenations are "built" and only then does it dynamically allocate the space and give you back your string.

Il mio amico ha detto qualcosa sulla falsariga di

That may be true today, but if you are reliant on such optimizations, then you should make your own StringBuilder. In future versions, there's no reason that StringBuilder couldn't use simple string concatenation (str1 = str2 + str3). Libraries only guarantee functional equivalence, not runtime equivalence.

È vero per le biblioteche?

  • Se utilizzo la funzione Sort() di una libreria con runtime O(n*log(n)) , è possibile che una versione futura cambi il tempo di esecuzione in O(n^2) ?

Lo stesso vale per gli strumenti eseguibili?

  • Potrebbe (ad esempio) il tempo di esecuzione di grep cambiare radicalmente in futuro?

A parte questo, non sarebbe una buona pratica per uno sviluppatore di librerie / API / strumenti mantenere i runtime per le stesse chiamate simili nel tempo?

    
posta Frank Bryce 15.01.2016 - 17:06
fonte

2 risposte

5

Risposta breve: non è vero per le librerie o gli strumenti "in generale". Ogni venditore può garantire per la sua biblioteca o strumento ciò che vuole. Esistono librerie e strumenti in cui il fornitore garantisce

  • equivalenza funzionale e l'equivalenza di alcuni aspetti dei requisiti non funzionali
  • solo equivalenza funzionale, non più
  • solo equivalenza sintattica
  • nessuno dei precedenti

E anche se un venditore ti garantisce qualcosa per una versione specifica o una versione di un prodotto, nessuno può impedirgli legalmente di creare una nuova versione o una nuova linea di prodotti con un'API diversa o un comportamento non funzionale diverso. Quindi la domanda "può essere modificata" non è realmente quella giusta, dovresti invece chiedere "quanto è probabile per uno strumento o una libreria specifici?"

Per il tuo esempio della classe StringBuilder , IMHO è assurdamente improbabile che MS cambierà il suo comportamento durante l'esecuzione all'interno del framework .NET in un modo tale che lo sforzo di scrivere una classe del genere te ne varrà mai la pena La citazione del tuo amico suona più come sciocchezza superstiziosa un malinteso eccessivo per me, almeno per questo caso.

Microsoft ha aggiunto una classe di questo tipo esplicitamente al framework .NET per fornire un'alternativa mutabile alla classe String immutabile tenendo conto di alcuni aspetti delle prestazioni, la documentazione di quella classe è molto dettagliata a riguardo. In passato MS ha cercato di mantenere le versioni più recenti del framework .NET in gran parte compatibili con versioni precedenti, anche se ciò significa non correggere alcuni bug o vivere con imperfezioni. E cambiare il comportamento del tempo di esecuzione di un StringBuilder in modo significativo non interromperà solo il tuo programma, ma molto probabilmente decine di migliaia di altri programmi - StringBuilder è una delle classi centrali centrali del framework, e ampiamente usato tra i Ecosistema .NET. Questo non è niente che qualsiasi ragionevole venditore di biblioteche cambierebbe alla leggera. Quando infastidiscono troppo i loro clienti, i clienti iniziano a cercare un fornitore diverso e questo gli costerà dei soldi.

Lo stesso vale per molti altri fornitori di strumenti o biblioteche e coloro che non si prendono cura di questo rischio infastidiscono i loro clienti finché non cercano un altro fornitore.

Per darti un altro esempio: la libreria standard C ++ fornisce specifiche esplicite per il comportamento del tempo di esecuzione di std :: sort, è garantito che sia O(n * log(n)) per il caso medio, vedi Wikipedia .

E per la domanda di "grep": sono abbastanza sicuro che esistano già implementazioni diverse di grep da diversi vecchi sistemi unix o unix-like, e sarei stupito se avessero tutti lo stesso comportamento in fase di esecuzione. Lo standard Posix consente di avere gli stessi switch della riga di comando, almeno per qualsiasi SO conforme a Posix. Tuttavia, oggigiorno il fatto che Linux incluso GNU grep sia così popolare, puoi probabilmente fare affidamento anche sul suo comportamento non funzionale almeno su qualsiasi sistema Linux decente.

    
risposta data 15.01.2016 - 17:48
fonte
3

...if you are reliant on such optimizations, then you should make your own ...

È un po 'una tautologia per dirlo, ma il codice garantisce solo ciò che garantisce. Uno degli scopi di avere le librerie è di formare un confine che è opaco per i chiamanti, e l'unica volta che dovrebbe esserci un reclamo è quando una delle garanzie non viene soddisfatta. (Questo concetto è al centro di design per contratto .)

Il tuo collega dice che se ti affidi a una particolare implementazione, hai stabilito requisiti che vanno oltre le garanzie originali. Ciò non significa che devi scrivere il tuo, ma non puoi passare a un'altra implementazione finché non hai verificato che soddisfa tutti i requisiti.

If I use a library's Sort() function that has runtime O(n*log(n)), is it possible that a future version would change the runtime to O(n^2)?

Certo. Dubito che qualcuno lo farebbe intenzionalmente a meno che qualcuno non abbia detto "Ho bisogno che tu faccia rallentare questo codice". Una versione futura potrebbe eseguire meglio , che è qualcosa che piace a molti. Ma, ancora una volta, se si dipende dalla libreria per operare in un determinato periodo di tempo, un'implementazione più veloce non soddisferà i requisiti e interromperà il software.

... wouldn't it be good practice for a library/API/tool developer to keep runtimes for the same calls similar over time?

Non proprio. L'implicazione reductio ad absurdum sarebbe che le implementazioni dovrebbero essere immutabili perché qualcuno potrebbe essere diventato dipendente dal comportamento scorretto causato da un bug. Le uniche modifiche che potresti apportare sarebbero le aggiunte di funzioni che fanno cose completamente nuove o sono versioni modificate di quelle già esistenti (ad esempio foo() , foo_version_2() , ecc.). Ci sono alcuni casi molto rari in cui ciò è auspicabile, ma la maggior parte delle volte, se pensi di averne bisogno, dovresti probabilmente ripensarci.

La buona pratica per gli sviluppatori di librerie è quella di documentare le modifiche in modo che gli utenti della biblioteca possano capire cosa è cambiato. Le buone pratiche per gli utenti di tale libreria sono comprendere le modifiche e gli effetti sul proprio codice prima di distribuirli. La cattiva pratica è quella di inserire una nuova versione di una libreria solo perché ne è stata resa disponibile una.

Tutto questo si applica a interi programmi nello stesso modo in cui si applica alle librerie. La maggior parte delle persone si aspetta che l'interruttore -x in grep(1) stamperà solo le linee che corrispondono esattamente al modello. Un cambiamento nel comportamento tra le versioni spezzerà le cose che dipendono da esso e richiederà che le dipendenze cambino o che la vecchia versione rimanga al suo posto.

    
risposta data 16.01.2016 - 14:37
fonte

Leggi altre domande sui tag