MokaByte 48 - Gennaio 2001
Foto dell'autore
di
Matteo Baccan
Java vs C#
Primo confronto fra i due linguaggi
Con la nuova versione di Visual Studio, Microsoft abbandonerà Java per dedicarsi ad un nuovo linguaggio, chiamato C#. Proviamo ora a confrontare questo linguaggio con Java per capire dove e se ci sarà uno scontro tra queste due tecnologie e dove converrà l’utilizzo di una o l’utilizzo dell’altra.

Come spesso succede, prima che un prodotto veda la luce, la potente macchina marketing dell’azienda che lo sviluppa si mette in moto per promuoverlo o per iniziare a far parlare del prodotto, prima che sia pronto. Per questa ragione escono libri, interviste, articoli di vario genere, gruppi di discussione, siti e preview.
Circa un anno fa il marketing di Microsoft si è messo in moto per C#, da leggere C sharp, che molti di voi sicuramente hanno gia avuto modo di incrociare lungo la rete.
C# non è altro che il linguaggio che andrà a sostituire Java nella prossima versione di Visual Studio, che nasce pensato per poter essere il linguaggio principale per lo sviluppo di applicazioni all’interno del framework .NET.
L’abbandono di Java libera Microsoft dai problemi nei confronti di SUN. Primo fra tutti il vincolo di non poter ampliare un linguaggio come Java e di non poter rendere attive di default le proprie estensioni.
Inoltre permette a Microsoft di riutilizzare gran parte del pensiero che si trova alle basi di Java all’interno di un nuovo linguaggio, nato per essere allo stesso tempo object oriented e semplice da usare e per poter sfruttare sin dal principio l’immensa collezione di librerie scritte per Windows.
 
 
 

Perché C#
I linguaggi maggiormente utilizzati in ambiente Windows sono sicuramente Visual Basic e Visual C++, almeno per quello che riguarda Microsoft. Col passare del tempo i nuovi sviluppi tecnologici hanno obbligato Visual C++, e in modo più pesante Visual Basic, ad imbottirsi di nuovi costrutti, librerie e wizard, in modo da riuscire a creare tutto quello che in sistema operativo come Windows permetteva di fare.
Col tempo quest’approccio ha modificato questi linguaggi che dovevano però rimanere, nel limite del possibile, retrocompatibili.
Perché allora non creare un nuovo linguaggio che potesse sfruttare la semplicità di Java, libero da ogni vincolo col passato e che pronto ad utilizzare il framework di oggetti gia disponibile in ambiente Windows? Inoltre perché non pensarlo in modo da essere portabile fra processori di generazioni diverse, rendendo semplice, ad esempio, il passaggio di architettura da 32 a 64 bit?
Microsoft diede allora a Anders Hejlsberg, per chi non lo ricorda la mente dalla quale nacquero Turbo Pascal e Delphi, il compito di studiare un “qualcosa” che potesse dare una valida risposta a queste esigenze. Da questo lavoro nacque C#.

Le caratteristiche di C# sono:
 

  • Semplicità di utilizzo. Come Java, si è semplificato lo sviluppo di codice evitando le dichiarazioni forzate di funzioni, come accade in C e C++. Si sono rimossi i legami con i processori e sono state introdotte delle funzionalità per riuscire a scrivere in maniera semplice applicazioni Internet Based e Multithread Oriented.
  • Integrazione diretta con COM (Component Object Model). Per riuscire a scrivere ed utilizzare oggetti COM in maniera semplice ed intuitiva, sono stati introdotti una serie di costrutti nel linguaggio ed una serie di classi che rendessero semplice il dialogo fra C# e COM.
  • Integrazione con l’ambiente .NET. C# si propone come lo strumento di sviluppo del nuovo ambiente .NET di Microsoft. Questo si capisce dalla notevole mole di codice C# presente in tutti gli esempi di utilizzo del framework esistenti al momento.


Queste sono solo alcune delle caratteristiche di C#, ma probabilmente le principali. Inoltre sono quelle che dovrebbero motivare un programmatore a sceglierlo come linguaggio di sviluppo.
In sintesi: “lavori o vuoi lavorare con .NET? Allora C# è la scelta migliore”.
Vediamo ora quali sono invece i punti di forza di Java e perché si dovrebbe scegliere questo linguaggio.
 
 

Perchè Java
Da programmatore Java mi sembra perifno inutile  scrivere le motivazioni che spingono ad utilizzarlo come linguaggio. Sono sicuramente molteplici, ma le maggiori sono date da:
 

  • Semplicità d’uso. Sono stati abbattuti molti vincoli rispetto a linguaggi come C++, che permettono la scrittura di codice lineare e potente.
  • Nella definizione di linguaggio sono già presenti le specifiche per l’utilizzo di database SQL. Questo fatto non obbliga a nessun particolare artificio per utilizzare un programma Java, a parità di JDK, in una piattaforma piuttosto che un'altra. La stessa operazione in altri linguaggi si rivela molto costosa a livello implementativo.
  • Definizione di Socket e Thread a livello di linguaggio. Java nasce pensato per Internet, dove il protocollo utilizzato è TCP/IP. Il fatto di avere, nel framework di classi base, la classe Socket ci permette di scrivere applicazioni Internet supportate da tutte le piattaforme che implementano Java. Altri linguaggi, come C, non hanno tale implementazione a livello di framework base e quindi obbligano ad avere implementazioni diverse da sistema operativo a sistema operativo. Stesso discorso per i Thread indispensabili per qualsiasi applicazione che fornisca servizi all’interno di una rete.
  • Portabilità. Mi è capitato più volte di scrivere programmi che dovevano essere utilizzati in piattaforme diverse da quella di sviluppo. Pur utilizzando Windows come ambiente di sviluppo primario e AIX come target, sistemi operativi completamente diversi, non ho mai avuto problemi nel passaggio di applicazioni da un sistema all’altro. Tutto questo grazie all’architettura di questo linguaggio, sicuramente ben definita.


Le motivazioni che possono spingere ad utilizzare Java sono molto maggiori, ma credo possano variare da applicazione ad applicazione, mentre queste poche possono sicuramente proporsi come le più sentite.
 
 
 

Convergenza o divergenza?
Come abbiamo visto, entrambi i linguaggi aspirano alla semplicità. Le complessità delle moderne applicazioni rischiavano di far diventare i vecchi linguaggi di programmazione troppo complessi da utilizzare, per la stesura delle applicazioni che oggi si è costretti a scrivere.
Ognuno dei due però si distingue per il target che vuole colpire. C# vuole essere il linguaggio primario di .NET e Java il linguaggio primario di Internet.
A questo punto vediamo di entrare maggiormente in dettaglio nel codice per capire cosa differenzia C# da Java.
 
 

Figura 1: Il debugger di C#

 

Confronto
Per una corretta analisi delle funzionalità dei due linguaggi, cominciano col confrontare il programma più piccolo che si può fare con Java e con C#, cioè il classico ”Hello World”.
Ecco di seguito le due implementazioni. Per quello che riguarda Java:

public class test {
   public static void main(String[] args) {
      System.out.println("Ciao Mondo");
   }
}

per quello che riguarda C#:

class test {
   static void Main(string[] args) {
      System.Console.WriteLine("Ciao Mondo");
   }
}

Come si può notare la struttura è molto simile. In entrambi i casi si tratta di una classe principale con un metodo predefinito statico che prende come argomento un array di stringhe.
In entrambi i casi è poi possibile accedere direttamente all’oggetto System ed utilizzare lo standard output per stampare una riga.
Molto simile è anche la dichiarazione di una classe esterna, che in Java viene fatta tramite il comando import e in C# tramite il comando using:

// Java
import java.lang.System;

// C#
using System;
 
 
 
 

Figura 2: I parametri di compilazione di C#

 

Statement
Derivando entrambi da C, non ci sono molte differenze negli statement utilizzabili in questi due linguaggi. Ad esempio è identico l’utilizzo di:

- if/then/else
- switch
- while
- do while
- break/continue
- return
- new

L’unica differenza è data dal fatto che C# introduce un costrutto nuovo che è foreach.
Foreach serve per accelerare la scansione di un array, evitando di scrivere il codice che legge un singolo valore. Ad esempio il seguente codice Java:

// Assumendo che vector sia un oggetto della 
// classe java.util.Vector
int tot = 0;
for (int nCur = 0; nCur < vector.size(); nCur++) {
   // Viene preso l’elemento ennesimo
   int i = (Integer)vector.elementAt(nCur);
   // E il suo valore viene aggiunto al totale
   tot += i;
}

In C# invece si sarebbe potuto scrivere:

// Assumendo che vector sia un oggetto della 
// classe ArrayList
int tot = 0;
foreach (int i in vector) {
   // aggiungo il valore al totale
   tot += i;
}
 
 
 
 
 

Figura 3: L’uso delle property

 

Eccezioni
Altro particolare interessante è dato dall’opzionalità del costrutto try/catch/finally.
Se in Java volessi, con una catch, gestire tutte le eccezioni di una certo blocco di codice, dovrei scrivere qualcosa di molto simile a questo:

try{
   // Codice
} catch (Throwable e){
   // Gestione delle eccezioni
}

questo perché il ramo di catch, in un try, è obbligatorio.
In C# non è obbligatorio, ed è possibile scrivere tranquillamente:

try{
   // Codice
} catch {
   // Gestione delle eccezioni
}

omettendo di specificare quale oggetto deve gestire la catch. Inoltre è anche possibile omettere completamente la parte di catch, l’importante è definire almeno la clausola finally.

Definizione delle classi e sincronizzazioni
Anche in questo caso ci sono delle differenze nella definizione, ma sono relative soprattutto al modo col quale debbono essere scritte le varie modalità di ereditarietà. Ad esempio i costrutti Java:

class A extends B {
   // implementazione
}

interface IA extends IB {
   // implementazione
}

class C implements IA, IB {
   // implementazione
}

Vengono implementati in C# allo stesso modo di C++:

class A : B {
   // Implementazione 
}

interface IA : IB {
   // Definizione
}

class C: IA, IB {
   // Implementazione
}

quindi non viene definita una keyword diversa per estendere od implementare una classe o un’interfaccia, ma viene genericamente utilizzato il simbolo di ‘:’.
Un'altra leggera differenza è data anche dalla gestione del costrutto synchronized, che in C# funziona allo stesso modo, ma è chiamato più semplicemente lock.
 
 
 

Figura 4: L’uso di api 
Windows

 
 

Estensioni di C#
Analizziamo ora alcune delle novità che, un linguaggio nuovo come C#, offre.
Una gradita sorpresa è data dalle properties, e qui probabilmente un piccolo influsso da Delphi si inizia a vedere.
Il costrutto properties permette di definire una variabile distanza pubblica interrogabile ed assegnabile all’interno di un oggetto, e fino a qui nulla di particolare. La cosa interessante è data dal poter definire, in modo esplicito, una funzione che controlla l’assegnazione a tale variabile ed una che ne controlla la lettura.
Con Java si può ottenere lo stesso effetto gestendo due funzioni di set e get. La prima che gestisce l’assegnazione e la seconda che controlla l’interrogazione.
Per semplificare il tutto in C# si è optato per il costrutto properties. Osservate il seguente esempio.
Nella parte di Main viene definito un oggetto test e viene assegnato, ad una sua variabile d’istanza numero, il valore 10. Successivamente tale valore viene preso e visualizzato a video. Proviamo però ad osservare com’è stata implementata questa variabile all’interno della classe test:

class test {
   static void Main(string[] args) {
      test x = new test();
           x.numero = 10;
      System.Console.WriteLine( "Valore = " +x.numero );
   }

   private int nNum = 0;
   public int numero {
      get {
         System.Console.WriteLine("Legge valore");
         return nNum;
      }
      set {
         System.Console.WriteLine("Scrive valore");
         nNum = value;
      }
   }
}

le due funzioni get e set permettono di controllare perfettamente l’accesso a numero.
Anche se questo costrutto può sembrare superfluo, sicuramente rende molto più semplice la scrittura di codice. Inoltre permette di intervenire in quei casi in cui si sia esposta una variabile di istanza la cui gestione debba essere successivamente controllata.
 
 
 
 

Figura 5: Il debugger visuale

 

Unificazione fra tipi primitivi ed oggetti 
Un altro particolare interessante di C# è dato dall’unificazione fra i tipi base e gli oggetti.
Questo vuol dire che, ad esempio, non occorre convertire un numero in un oggetto per averne il corrispettivo String come in Java:

Integer i = new Integer(1971);
System.out.println(i.toString());

ma basta applicare il metodo ToString direttamente al numero:

System.Console.WriteLine(1971.ToString());

Questo vuol dire che tutto in C# è una sottoclasse di object, anche i tipi base che in Java non lo sono.
 
 
 

Strutture ed enum
Le strutture erano state volutamente rimosse da Java, ma in C# riappaiono.
L’unica estensione introdotta è la possibilità di aggiungere costruttori e metodi.
Diciamo che la struttura diventa così una piccola classe, col vincolo di non poter ereditare da un'altra struttura.
Un’altra importante caratteristica delle strutture è data dal loro utilizzo per valore e non per riferimento. Questo vuol dire che, in caso di passaggio di parametri tra metodi, la struttura viene passata interamente sullo stack, mentre se fosse un oggetto ne sarebbe passato solo il suo riferimento.
Per quello che riguarda le enum il concetto è identico a quello presente in C. Vi è la possibilità di definire oggetti con parametri letterali, facendo gestire in automatico dal compilatore la loro gestione. Java tende invece a sopprimere questo concetto, utilizzando semplicemente dei valori numerici di tipo final static ed ottenendo, a tutti gli effetti, lo stesso meccanismo.
 
 
 
 
 
 

Codice Nativo
C# nasce anch’esso con l’idea di non produrre del codice nativo per una determinata piattaforma, ma del codice intermedio. In questo modo è possibile, e qui Java insegna, portare i programmi scritti in C# su altre piattaforme.
In realtà esiste una feature che potrebbe dare fastidio a questo porting automatico. Tale fastidio è dato dalla facilità con la quale è possibile scrivere del codice che interroga direttamente API Windows o richiama funzioni C.
Il concetto è simile a JNI, ma molto più semplice da attuare, ad esempio per chiamare la funzione MessageBoxA è sufficiente dichiarare l’utilizzo della dll user32.dll e dichiarare un metodo come extern.

using System;
class MyClass
{
   [sysimport(dll="user32.dll")]
   public static extern int 
      MessageBoxA(int h, string m, string c, int type);

   public static int Main() {
      return MessageBoxA(0, "Hello World!", "Caption", 0);
   }
}

Per chi ha utilizzato Java SDK di Microsoft, questa tecnica è praticamente identica a quella utilizzata nell’implementazione Java di tale prodotto.
In Java, per poter fare la stessa cosa, occorre scrivere del codice direttamente in C.
Non mi sento però di criticare fino in fondo questo approccio.
Da un lato l’implementazione di Java è corretta. Rendere troppo semplice l’interfacciamento con codice “non puro” può compromettere il concetto alla base del linguaggio, che è quello di scrivere un programma il più portabile possibile.
D’altro canto è anche vero che, se ci fosse l’esigenza di fare una chiamata ad una libreria di sistema, obbligare il programmatore a scrivere codice C, quando si poteva risolvere tutto con dei semplici costrutti, sarebbe molto più semplice.
 
 
 

Conclusioni
Alla luce dello sviluppo attuale, la miglior scelta per la scrittura di applicazioni stabili, non può che ricadere che su Java. È molto potente, semplice, fruibile e l’ambiente di sviluppo può essere scaricato gratuitamente dalla rete. Inoltre ha numerose librerie di supporto ed i maggiori ambienti di sviluppo esistenti lo supportano. Java è un linguaggio facilmente trasportabile da piattaforma a piattaforma senza nessuna particolare cura durante la scrittura di codice.
C# invece risulta ancora troppo giovane come linguaggio di programmazione, soprattutto perché non esiste ancora una versione 1.0. Inoltre non si riesce ancora a capire quanto può risultare stabile e quando potrà essere utilizzato fuori dalla piattaforma .NET.
Non sarà sempre così. Non appena il linguaggio di stabilizzerà ed inizieranno ad uscire le prime versioni, sicuramente, sarà uno dei linguaggi più semplici per la scrittura di applicazioni Windows. Inoltre, non avendo legami col passato, sarà molto lineare scrivere applicazioni in C#, con grande gioia dei programmatori, che troveranno maggiormente facile scrivere un componente in C# piuttosto che in C++ o Visual Basic.

Gli esempi descritti in questo articolo possono essere scaricati da qui
 
 
 

Bibliografia
[1] http://www.microsoft.com. Homepage di Microsoft dove scaricare il preview di .NET
[2] http://java.sun.com. sito SUN dal quale scaricare l’ultima versione di JDK.
[3] http://windows.oreilly.com/news/seesharp_0700.html. "C# Is Pronounced 'See Sharp,'" Arthur Griffith (windows.oreilly.com).
[4] http://www.javaworld.com/javaworld/jw-11-2000/jw-1122-csharp1.html. C#: A language alternative or just J--?, Part 1.
[5] http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-csharp2_p.html. C#: A language alternative or just J--?, Part 2.
[6] http://www.infomedia.it/artic/Baccan, sito contenente alcuni articoli di approfondimento degli argomenti trattati.

Matteo Baccan è uno specialista di progettazione e sviluppo in C++, Java e Lotus Notes. Attualmente si occupa dello studio di tecniche avanzate di programmazione in ambito Internet/Intranet tramite Lotus Notes e Java, presso Integra Italia. Si possono consultare alcune sue pubblicazioni presso http://www.infomedia.it/artic/Baccan. Può essere contattato tramite e-mail all'indirizzo mbaccan@mokabyte.it
 

Vai alla Home Page di MokaByte
Vai alla prima pagina di questo mese


MokaByte®  è un marchio registrato da MokaByte s.r.l.
Java® è un marchio registrato da Sun Microsystems; tutti i diritti riservati
E' vietata la riproduzione anche parziale
Per comunicazioni inviare una mail a
mokainfo@mokabyte.it