Sono ancora necessari tipi specifici?

20

Una cosa mi è venuta in mente l'altro giorno, sono ancora necessari tipi specifici o un'eredità che ci trattiene. Quello che voglio dire è: abbiamo davvero bisogno di brevi, int, lunghi, bigint ecc ecc.

Capisco il ragionamento, le variabili / oggetti sono tenuti in memoria, la memoria deve essere allocata e quindi abbiamo bisogno di sapere quanto può essere grande una variabile. Ma in realtà, non dovrebbe un linguaggio di programmazione moderno essere in grado di gestire "tipi adattivi", cioè, se qualcosa viene sempre assegnato solo nell'intervallo corto usa meno byte e se a qualcosa viene assegnato improvvisamente un numero molto grande viene assegnata la memoria accordinly per quell'istanza particolare.

Float, real e double sono un po 'più complicati in quanto il tipo dipende dalla precisione di cui hai bisogno. Le stringhe dovrebbero tuttavia essere in grado di prendere una memoria inferiore in molti casi (in .Net) dove per lo più si usa ASCII, ma le stringhe di sempre prendono il doppio della memoria a causa della codifica Unicode.

Un argomento per tipi specifici potrebbe essere che fa parte della specifica, per esempio una variabile non dovrebbe essere in grado di essere più grande di un certo valore, quindi lo impostiamo in shortint. Ma perché non avere vincoli di tipo, invece? Sarebbe molto più flessibile e potente essere in grado di impostare intervalli e valori consentiti su variabili (e proprietà).

Mi rendo conto dell'immenso problema nel rinnovare l'architettura dei tipi poiché è così strettamente integrato con l'hardware sottostante e cose come la serializzazione potrebbero diventare davvero complicate. Ma dal punto di vista della programmazione dovrebbe essere bello no?

    
posta Homde 02.02.2011 - 21:05
fonte

10 risposte

12

Sono assolutamente convinto che sia così. I vincoli semantici valgono più dei vincoli di implementazione. Preoccuparsi delle dimensioni di qualcosa sembra preoccuparsi della velocità di qualcosa quando si verificava una programmazione orientata agli oggetti.

Non ha sostituito la programmazione critica delle prestazioni. È semplicemente reso la programmazione critica non performante più produttiva.

    
risposta data 02.02.2011 - 21:22
fonte
9

Tipi adattativi significa logica per fare l'adattamento, significa lavorare in runtime per eseguire quella logica (il template e il tempo di compilazione richiederebbe un tipo specifico, digitare inferenza essere un caso speciale in cui ottieni il meglio dei due mondi). Quel lavoro in più potrebbe essere ok in ambienti in cui le prestazioni non sono critiche, e il sistema mantiene una dimensione ragionevole. In altri ambienti non lo è (i sistemi incorporati ne sono uno, in cui a volte è necessario utilizzare i tipi interi 32/64 bit per le prestazioni della cpu e i tipi interi 8 / 16bit per l'ottimizzazione del backup della memoria statica).

Anche le lingue generiche che supportano l'associazione tardiva (risoluzione dei tipi in fase di runtime, come VB6) tendono a promuovere digitando ora (VB.NET), a causa del colpo di prestazioni che si verificava quando l'associazione tardiva veniva abusata, e perché spesso si finisce con un brutto codice quando i tipi non sono espliciti ( Riferimento / Refactoring professionale in Visual Basic - Danijel Arsenovski ).

    
risposta data 02.02.2011 - 21:19
fonte
4

Semplicità, memoria e velocità Quando dichiaro una variabile, la memoria per quella variabile è allocata in un blocco. Per supportare una variabile che cresce dinamicamente, dovrei aggiungere il concetto di memoria non contigua a quella variabile (o quella o riservare il blocco più grande che la variabile può rappresentare). La memoria non contigua ridurrebbe le prestazioni sull'assegnazione / recupero. Assegnare il massimo possibile sarebbe uno spreco nello scenario in cui ho solo bisogno di un byte ma il sistema riserva un lungo tempo.

Pensa ai compromessi tra una matrice e un vettore (o una lista collegata). Con un array, la ricerca di una posizione specifica è una semplice questione di ottenere la posizione di partenza e spostare il puntatore di memoria x spazi per individuare quella nuova posizione in memoria. Pensa a un int come un bit [32] leggendo un int è necessario attraversare quell'array per ottenere tutti i valori di bit.

Per creare un tipo di numero dinamico, devi cambiarlo da una serie di bit a un vettore di bit. Leggere il tuo numero dinamico implica andare alla testa, ottenere quel bit, chiedere dove il prossimo bit è in memoria, spostarsi in quella posizione, ottenere quel bit, ecc. Per ogni bit nel numero dinamico, stai facendo tre operazioni di lettura ( corrente), leggi (indirizzo successivo), sposta (successivo). Immagina di leggere i valori di un milione di numeri. Questo è un milione di operazioni extra. Potrebbe sembrare insignificante. Ma pensa ai sistemi (come i finanziari) in cui ogni millisecondo conta.

È stata presa la decisione che mettere l'onere sullo sviluppatore per controllare le dimensioni e convalidare è un piccolo compromesso rispetto alle prestazioni del sistema.

    
risposta data 02.02.2011 - 21:38
fonte
3

Sono richiesti tipi specifici per linguaggi e progetti incentrati sull'hardware. Un esempio sono i protocolli di rete on-the-wire.

Ma creiamo - per divertimento - un tipo varint in una lingua come il C ++. Costruiscila da un new 'd array di ints.

Non è difficile implementare l'addizione: solo xorare i byte insieme e controllare i bit alti: se c'è un carry opereration, new in un nuovo byte superiore e portare il bit sopra. La sottrazione segue banalmente nella rappresentazione del complemento a 2. (Questo è anche noto come trasduttore di ripple)

La moltiplicazione segue in modo simile; usa l'aggiunta / spostamento iterativo. Come sempre, la vera svolta nella tua coda è la divisione [*].

Che cosa hai perso quando ciò accade, però?

  • Tempo deterministico. Hai un syscall ( new ) che può attivarsi in punti che non sono necessariamente controllabili.

  • Spazio deterministico.

  • La matematica semi-software è lenta.

Se hai bisogno di usare un linguaggio a livello hardware e devi anche operare a un livello alto (lento) e non vuoi incorporare un motore di scripting, un varint rende molto senso. Probabilmente è scritto da qualche parte.

[*] C.f. algoritmi matematici hardware per modi più veloci di farlo - di solito il trucco sono le operazioni parallele.

    
risposta data 02.02.2011 - 22:39
fonte
2

Questa è una buona domanda. Spiega perché un linguaggio come Python non ha bisogno di "short, int, long, bigint ecc.": Gli interi sono, beh, interi (c'è un singolo tipo intero in Python 3), e non hanno dimensioni limite (oltre a quella di la memoria del computer, ovviamente).

Come per Unicode, la codifica UTF-8 (che fa parte di Unicode) utilizza solo un singolo carattere per i caratteri ASCII, quindi non è poi così male.

Più in generale, le lingue dinamiche sembrano andare nella direzione che hai menzionato. Tuttavia, per motivi di efficienza, in alcuni casi sono utili tipi più vincolati (come i programmi che devono essere eseguiti velocemente). Non vedo molti cambiamenti nel prossimo futuro, dato che i processori organizzano i dati in byte (o 2, 4, 8, ecc. Byte).

    
risposta data 02.02.2011 - 22:24
fonte
1

Su basi di teoria linguistica hai ragione. I tipi dovrebbero essere basati su una serie di stati legali, le trasformazioni disponibili per tali stati e le operazioni eseguibili su quegli stati.

Questa è approssimativamente la programmazione OOP nella sua forma tipica, tuttavia. Infatti, in Java, stai effettivamente parlando delle classi BigInteger e BigDecimal , che allocano lo spazio in base a quanto è necessario per archiviare l'oggetto. (Come notato da FrustratedWithFormsDesigner, molti linguaggi di scripting sono ancora più avanti lungo questo percorso e non richiedono nemmeno una dichiarazione di tipo e memorizzeranno qualunque cosa tu gli dai.)

Le prestazioni sono comunque rilevanti, e dato che è costoso cambiare i tipi in fase di esecuzione e poiché i compilatori non possono garantire la dimensione massima di una variabile in fase di compilazione, abbiamo ancora variabili di dimensioni statiche per tipi semplici in molte lingue .

    
risposta data 02.02.2011 - 21:33
fonte
1

Dipende dalla lingua. Per linguaggi di livello superiore come Python, Ruby, Erlang e così hai solo il concetto di numeri interi e decimali.

Tuttavia, per una certa classe di linguaggi che hanno questi tipi sono molto importanti. Quando si scrive codice per leggere e scrivere formati binari come PNG, JPeg, ecc. È necessario sapere con precisione quante informazioni vengono letti contemporaneamente. Stessa cosa con la scrittura dei kernel del sistema operativo e dei driver di dispositivo. Non tutti lo fanno, e nelle lingue di livello superiore usano le librerie C per fare il lifting dettagliato.

In short , c'è ancora spazio per i tipi più specifici, ma molti problemi di sviluppo non richiedono quella precisione.

    
risposta data 02.02.2011 - 22:35
fonte
0

Recentemente ho creato un editor logico ladder e un runtime e ho deciso di essere molto limitato con i tipi:

  • booleana
  • Numero
  • Stringa
  • DateTime

Credo che lo abbia reso più intuitivo per l'utente. Questo è un allontanamento radicale dalla maggior parte dei PLC che hanno tutti i tipi "normali" di tipi che si vedono in un linguaggio come C.

    
risposta data 02.02.2011 - 21:52
fonte
0

I linguaggi di programmazione si sono mossi in quella direzione. Prendi le corde per esempio. Nei vecchi linguaggi devi dichiarare la dimensione della stringa, come PIC X(42) in COBOL, DIM A$(42) in alcune versioni di BASIC o [ VAR ] CHAR(42) in SQL. Nei linguaggi moderni hai solo un tipo string con allocazione dinamica e non è necessario pensare alle dimensioni.

I numeri interi sono diversi, tuttavia:

What I mean is: do we really need short, int, long, bigint etc etc.

Dai un'occhiata a Python. Serviva a distinguere tra numeri interi ( int ) e numeri interi ( long ). In 3.x il primo è scomparso (il vecchio long è il nuovo int ) e nessuno lo manca.

Ma c'è ancora un tipo specializzato per sequenze di interi a 8 bit sotto forma di bytes e bytearray . Perché non utilizzare rispettivamente tuple o list di numeri interi? Vero, bytes ha metodi stringa aggiuntivi che tuple non ha, ma sicuramente l'efficienza ha avuto molto a che fare con esso.

Float, real and double's are a bit trickier since the type depends on what precision you need.

Non proprio. L'approccio "tutto è a doppia precisione" è molto comune.

    
risposta data 03.02.2011 - 08:09
fonte
0

Capisco il ragionamento, le variabili / oggetti sono tenuti in memoria, la memoria deve essere allocata e quindi abbiamo bisogno di sapere quanto può essere grande una variabile. Ma in realtà, non dovrebbe un linguaggio di programmazione moderno essere in grado di gestire "tipi adattivi", cioè, se qualcosa viene sempre assegnato solo nell'intervallo corto usa meno byte e se a qualcosa viene assegnato improvvisamente un numero molto grande viene assegnata la memoria accordinly per quella particolare istanza.

Float, real e double sono un po 'più complicati in quanto il tipo dipende dalla precisione di cui hai bisogno. Le stringhe dovrebbero tuttavia essere in grado di prendere una memoria inferiore in molti casi (in. Net) dove per lo più si usa ASCII, ma le stringhe assumono sempre il doppio della memoria a causa della codifica Unicode.

Fortran ha avuto qualcosa di simile (non so se questo è esattamente ciò che intendi, dal momento che vedo davvero due domande). Ad esempio, in F90 verso l'alto non è necessario definire esplicitamente una dimensione del tipo , per così dire. Il che è positivo, non solo perché ti offre un posto centrale per definire i tuoi tipi di dati, ma anche un modo portatile per definirli. REAL * 4 non è la stessa in tutte le implementazioni su tutti i processori (e per processore intendo CPU + compilatore), non da un longshot.

selected_real_kind (p, r) restituisce il valore tipo di un tipo di dati reale con precisione decimale maggiore di almeno p cifre ed intervallo di esponente maggiore di almeno r.

Quindi, ad esempio;

program real_kinds
integer,parameter :: p6 = selected_real_kind(6)
integer,parameter :: p10r100 = selected_real_kind(10,100) !p is precision, r is range
integer,parameter :: r400 = selected_real_kind(r=400)
real(kind=p6) :: x
real(kind=p10r100) :: y
real(kind=r400) :: z

print *, precision(x), range(x)
print *, precision(y), range(y)
print *, precision(z), range(z)
end program real_kinds

(Penso che sia un esempio piuttosto auto-esplicativo)

Ancora non so se ho capito correttamente la tua domanda, e questo è quello che ti interessa.

    
risposta data 10.02.2011 - 18:29
fonte

Leggi altre domande sui tag