|
A
minha coluna intitulada “Porque a linguagem C# é melhor que a
linguagem Java” publicada no site da Microsoft em http://www.microsoft.com/brasil/msdn/colunas/falandoc/col_falandoc_2.asp
causou uma certa repercussão. Recebi muitas mensagens, algumas delas
até contendo dúvidas técnicas.
Acredito
que o C# seja superior ao Java. Também acho que a maioria das pessoas
intelectualmente honestas e que fizerem uma comparação objetiva vai
pensar o mesmo. Não era a idéia da coluna original ser um tratado
sobre as diferenças entre as duas linguagens e sim dar uma idéia
geral, como base para que o leitor pudesse pesquisar mais e fazer seus
próprios experimentos. Por esta razão, foram apresentadas comparações
em forma de tópicos, com poucas explicações. A ausência de explicações
detalhadas fez com que algumas pessoas tirassem conclusões
apressadas, por falta de conhecimento de C# e pouca disposição em
investigar. Neste artigo estou explicando alguns destes pontos com
maiores detalhes.
Respeito
quem usa e gosta da linguagem Java, a qual não acredito ter
menosprezado de forma alguma em meu artigo, muito pelo contrário.
Embora estivesse escrevendo para o site da Microsoft, forneci alguns
links que considero bem interessantes em locais que não são famosos
por gostarem do gigante de Redmond, como Doctor Dobbs Journal,
O’Reilly e até da própria Sun!
Para
o leitor que “não acha possível existir algo melhor que Java”,
gostaria que considerasse, além dos aspectos puramente técnicos, os
seguintes:
- O
C# foi desenvolvido DEPOIS do Java e indubitavelmente teve a
oportunidade de melhorar várias de suas deficiências - acredite,
elas existem. Por exemplo, nem o mais ferrenho defensor do Java
vai dizer que os programas Java têm excelente performance.
Pois bem, existem questões de performance intimamente
ligadas à linguagem e que foram “observadas” no C#. Veja
abaixo os comentários nas discussões sobre “enum”,
“structs”, “passagem por referência” e “ponteiros”,
para alguns exemplos.
- A
equipe que criou tanto o C#, como a nova plataforma de
desenvolvimento como um todo, tem em seu curriculum produtos
bastante respeitáveis: o Visual Basic, provavelmente a ferramenta
de desenvolvimento mais usada no mundo; o J++, em seu tempo a mais
popular ferramenta Java e o Delphi da Borland. Para quem não
sabe, Anders Hejsberg é o criador do Turbo Pascal, do Delphi e do
C# (*). Você pode até não gostar de alguma destas ferramentas,
mas é um curriculum sem dúvida respeitável.
- A
Microsoft investiu bastante na criação da nova plataforma de
desenvolvimento. Veja bem: uma equipe que é seguramente o melhor
pessoal do ramo, com dinheiro para gastar e sem a pressão de
precisar lançar um upgrade por trimestre para “fechar o balanço”
e não ir à falência.
Continuo
sem a intenção de escrever um tratado, mas vou dar algumas explicações
aos pontos que levantaram mais dúvidas. Os tópicos abordados a
seguir variam em importância, mas um bom resumo seria:
- O
C# tem intrinsecamente melhor performance que o Java;
- O
C# suporta conceitos de componentes (propriedades e eventos),
fundamentais para uma boa ferramenta RAD;
- O
C# restaura certos recursos úteis tirados do C++, como sobrecarga
de operadores, e acrescenta outros interessantes, como switch
com strings. A importância
destes recursos varia de pessoa para pessoa, mas acredito ser bom
tê-los à disposição.
(*)
Segundo a própria Borland, a Microsoft contratou 34 de seus
“funcionários-chave”, o que motivou uma ação na justiça e um
posterior “press-release” intitulado “BORLAND SUES MICROSOFT FOR
UNFAIR COMPETITION”. Este “press-release” foi recentemente
removido de seu site, não sei se com relação ao fato de eu tê-lo
citado há alguns meses atrás em um grupo de discussão da Borland.
Ainda é possível achar menções em outros sites como http://www.ugeek.com/techupdate/bldsuetc.htm,
http://www.informationweek.com/newsflash/nf629/0507_st10.htm,
http://news.zdnet.co.uk/story/0,,s2065714,00.html
e http://news.cnet.com/news/0-1005-200-318765.html?tag=.
Por freqüentar eventos internacionais como BORCON, Tech-Ed e PDC na
qualidade de “membro da imprensa”, eu conheci pessoalmente
pelo menos cinco destes ex-funcionários, todos envolvidos diretamente
com ferramentas de desenvolvimento. Um deles, Bill Dunlop, me
confessou há alguns anos atrás que ele “sentia-se em casa
trabalhando com tantos ex-funcionários da Borland”.
Todos os tipos
derivados de ancestral comum
Em
C#, todos os tipos podem ser tanto atribuídos a object
como ter métodos, NÃO APENAS AS CLASSES. Vou dizer de outra forma:
em C# você pode atribuir um int
diretamente a um object. Tem
mais: um int tem métodos! E
o melhor de tudo: quando você usar os inteiros “sozinhos”, você
não paga o preço adicional de OOP; estes tipos são gerenciados na
pilha de forma pouco custosa. Em Java você tem que gerenciar
manualmente “classes associadas” aos tipos intrínsecos.
Observe
o seguinte código C# que utiliza o recurso de “conversão automática
para referência”, também chamado de “boxing”. Note a ausência
de “classes wrapper”:
// Estes comandos não carregam o ônus de
criarem objetos
int
I = 123, J = 456;
int
Y = I + J;
// Agora um objeto será criado
automaticamente para ‘embalar’ o inteiro
// Note que o inteiro tem métodos!
string
s =Y.ToString();
Console.WriteLine(s);
// Podemos atribuir qualquer valor a um
object, até mesmo um inteiro!
object
O = s;
O = Y;
Console.WriteLine(O);
// Para pegar o inteiro de volta fazemos um
cast
int
Z = (int) O;
Console.WriteLine(Z);
// Uma lista pode conter qualquer coisa
ArrayList Lista = new
ArrayList();
Lista.Add("Maria tinha um carneirinho");
Lista.Add(false);
Lista.Add(123);
Lista.Add(34.56);
// Até mesmo instâncias de classes
Lista.Add(new
System.IO.StreamReader("teste.txt",
System.Text.Encoding.Unicode));
Veja um esquema do código e de como as variáveis
são alocadas:
É
até possível dizer que o C# é “mais orientado a objetos que o
Java” por possuir a unificação do sistema de tipos, como o
Smalltalk. Embora este tipo de argumentação seja subjetiva e estéril,
algumas pessoas acusam o C# de ser “menos orientado a objetos”
justamente por suportar structs e enums, apesar
das claras vantagens destes dois recursos.
O
argumento de que o Java é “mais orientado a objeto por não ter enum e struct” é o
mesmo que alguém dizer que “é mais brasileiro que outra pessoa
porque o outro sabe falar inglês”.
Propriedades
Uma
property funciona
sintaticamente como um campo, mas na verdade chama um par de métodos
para atribuir ou receber um valor. As propriedades podem ser também
"indexadas" com um inteiro, quando funcionam como se fossem arrays
ou indexadas com uma string,
quando passam a funcionar como dicionários. O ambiente de
desenvolvimento sabe criar "editores de propriedades" para
alterar seus valores em tempo de desenvolvimento.
O
Java sugere usar um padrão com dois métodos, GetXXX
e SetXXX. As propriedades não
só são conceitualmente mais simples para os programadores, como também
são muito importantes em ferramentas RAD. É possível emular
propriedades com um par de métodos, mas dá mais trabalho para quem
escreve tanto os componentes como os programas e ferramentas que as
usam.
Para
exemplificar como as propriedades têm uma sintaxe realmente específica
e de uso simples, veja o exemplo abaixo:
public
class ClassP {
//
Campo que vai armazenar o valor
string
fNome;
//
Propriedade
public
string Nome {
//
Pega o valor
get
{
return fNome;
}
//
Atribui o valor
set
{
fNome = value;
}
}
}
void
UsaProp() {
//
Cria objeto da classe
ClassP P = new
ClassP();
//
Atribui (chama o bloco set)
P.Nome = "Maria";
// Lê
o valor (chama o bloco get)
string
S = P.Nome;
}
Eventos
Podemos
declarar um tipo "ponteiro para método", chamado delegate. Um delegate contém,
a princípio, o endereço da função e também do método que a
implementa. Todos os eventos, tão importantes para o funcionamento de
um ambiente de desenvolvimento "RAD", são delegates.
Os delegates permitem que
uma classe chame métodos em outras sem exigir que esta outra classe
seja derivada de um ancestral conhecido. No artigo original, cito dois
links bastante interessantes sobre o assunto que estou repetindo a
seguir:
Artigo
da Sun "explicando" porque o Java não tem nem terá
delegates
Resposta
da Microsoft mostrando porque os delegates são úteis
As
principais vantagens dos delegates
sobre interceptar métodos virtuais de classes derivadas são as
seguintes:
- Os
eventos são conceitualmente mais simples, principalmente para o
programador médio;
- Os
eventos podem ser arbitrariamente associados em tempo de execução.
Interceptar um método virtual em tempo de execução exige a criação
de código, algo extremamente complicado, bem além da capacidade
de um programador médio e que exige um alto privilégio de
segurança, indisponível à maioria dos programas.
A
incorporação de eventos no finado J++ e na máquina virtual da
Microsoft foi uma das razões pelas quais a Sun abriu um processo - já
resolvido - contra a Microsoft. Até por esta razão, a Sun
dificilmente colocará eventos na linguagem, pois seria reconhecer que
a Microsoft estava “certa” ao alterar a linguagem.
Enums
As
enumerações em C# representam tipos à parte, incompatíveis entre
si e com inteiros, de forma muito semelhante ao Pascal. Embora
implementadas de forma eficiente como inteiros no executável final,
você não pode atribuir uma enumeração “de um tipo” à outra,
como poderia fazer com constantes inteiras.
As
bibliotecas Java como a “Swing”, por exemplo, usam geralmente strings
(“NORTH”, “SOUTH”, etc) em situações onde uma enumeração
seria mais aconselhável. O uso de strings
não apenas permite a verificação dos valores apenas em tempo de
execução, como também é bastante “cara” em termos de uso de
CPU e memória.
Veja
um exemplo em Java/Swing para ajuste de posição de componente de
tela:
contentPane.add(Button1,
BorderLayout.CENTER);
Note
que o posicionamento é especificado com string, algo bastante caro em
termos de execução. Para piorar, o código a seguir está errado,
mas compila com sucesso:
contentPane.add(Button1, “lixo”);
O
erro acima só será descoberto em tempo de execução. Uma enumeração,
além de ser mais “barata”, detectaria o erro em tempo de compilação.
Structs
A
struct é semelhante a class
no sentido que pode possuir coisas como “campos” e “métodos”.
As diferenças em relação a class são as seguintes:
- Elas
são tipos por valor enquanto as classes são tipos por referência
e, portanto, alocadas na pilha
- Não
podemos declarar um construtor que não aceite argumentos;
- Podemos
atribuir à variável this;
- Não
suportam herança; elas são implicitamente sealed.
Quando
devemos usar a struct ao invés
da class? A resposta é a seguinte: nos tipos “leves”, onde
uma classe sairia muito cara em termos de uso de CPU, memória e pressão
no coletor de lixo. O exemplo canônico é uma coordenada (X, Y) no
plano. Será que precisamos pagar o preço de uma classe para
implementar algo tão simples? Veja um esquema da memória usada por
uma class e uma struct
equivalentes:
Passagem por
referência
Em
Java, assim como no C#, existem “tipos por valor”, como os
inteiros e “tipos por referência”, como as instâncias das
classes. Quando de uma chamada de função, os “tipos por valor” são
passados por valor e os “tipos por referência” passados por referência.
Mas e se quisermos passar um “tipo por valor”, como um inteiro,
por referência? A resposta é que em Java não podemos. Precisamos
“embalar” o tipo por valor em uma classe, alocar a um objeto da
classe dinamicamente e aí passar o objeto, que “virou” uma referência.
Estas maquinações do Java têm um grande custo tanto em termos de
trabalho na programação como de performance.
Já
o C# inclui passagem por referência “tradicional”. Este é, aliás,
um recurso bastante útil que não havia no C, foi introduzido no C++
e retirado no Java. O C# o trouxe de volta.
A
vantagem do mecanismo do C# é que ele é bem mais “barato” que
embalar o valor em uma classe. Veja um exemplo bem simples:
static
void Soma(int
A, int B, out
int Resultado) {
Resultado
= A + B;
}
public
static void
Main() {
int a;
Soma(3, 4, out
a);
Console.WriteLine(a);
}
Documentação
em XML
O
Java tem uma ferramenta externa chamada Javadoc (http://java.sun.com/j2se/javadoc/)
que pode gerar páginas HTML com documentação a partir de tags
especiais colocadas no fonte.
O
C# também permite que se coloque tags no fonte com a finalidade de
criar documentação, mas o C# vai bem além da criação de páginas
HTML. Em primeiro lugar, o Visual Studio cria as tags automaticamente,
bastando digitar “///” antes do elemento a ser documentado.
Em
segundo lugar, a documentação fica imediatamente disponível dentro
do próprio Visual Studio como “dica”, sem que seja necessário
rodar qualquer ferramenta externa. Veja um exemplo:
Finalmente,
a documentação é disponibilizada em XML, não HTML. Por causa
disto, é muito fácil usar esta documentação de forma estruturada
para, por exemplo:
·
Converter
para HTML com uma style sheet XSL;
·
Efetuar
pesquisas;
·
Inserir
e manipular em bancos de dados.
Enquanto
a documentação do Javadoc pode ser apenas lida,
a do C# pode ser manipulada.
Ponteiros
Todas
as “instâncias” de classes, tanto em Java como em C# são
“referências”, uma espécie de “ponteiro domesticado”,
incapaz de apontar para endereços arbitrários de memória, ao contrário
de um ponteiro “comum” do C/C++. As duas linguagens também
verificam a faixa nos índices de arrays para evitar acesso indevido à memória. Ambos os recursos
contribuem para a criação de programas mais seguros e robustos.
Sendo
assim, para que precisamos de um ponteiro “cru”? Basicamente, em
duas situações:
- Chamar
DLLs: É muito bonito pensar que a biblioteca de runtime vai
resolver 100% dos seus problemas. Infelizmente, vão aparecer
situações onde você vai precisar acessar um dispositivo de
hardware ou rotinas de terceiros através de DLL. Um bom exemplo
é controlar impressoras fiscais. Postular a perfeição não
resolve o problema. Para estes casos, um programador Java terá
que fazer alguma séria ginástica, enquanto um programador C#
“liga o modo inseguro” e resolve o problema diretamente, sem
sair do ambiente. Na verdade, sem sair sequer do fonte; veja a
discussão a seguir sobre “Chamadas a código nativo”;
- Obter
melhor performance. Como os arrays
têm sempre a faixa validada em tempo de execução, algumas operações
que dependem da manipulação de grandes volumes de dados, como
por exemplo redes neurais e grafos em geral, vão ter um impacto
de performance bastante negativo. Novamente, o programador C# pode
“ligar o Turbo” e usar ponteiros para resolver o problema.
Não
estou advogando o uso indiscriminado de ponteiros. A própria .NET
Framework não incentiva o uso deste recurso, pois é necessário um
privilégio especial de segurança para rodar código contendo
ponteiros. Mas quando você precisar, o recurso estará à disposição.
Chamadas a código
nativo
O
Java permite chamadas a funções nativas através de “JNI”, mas
este recurso é bastante complexo, exige programação na linguagem C
(argh!) e ainda assim tem limitações. Se você não acredita em mim,
leia uma séria limitação no item 14 no final desta página no site
da Sun: http://java.sun.com/products/jdk/faq/jni-j2sdk-faq.html.
Para um exemplo de como chamar código nativo em Java, dê uma olhada
em um tutorial em http://java.sun.com/docs/books/tutorial/native1.1/stepbystep/index.html.
Note como é complicado!
Para
dar uma idéia da simplicidade do C#, veja um exemplo com chamada de
uma API do Windows (a API do Windows não é o melhor exemplo, pois
ela é encapsulada na .NET Framework, mas pelo menos é fácil de
testar):
[DllImport("user32.dll")]
public
static extern
int MessageBox(int
hWnd, string Msg, string
Titulo, int Tipo);
protected
void button2_Click (object
sender, System.EventArgs e) {
MessageBox(0,
"Mensagem de teste", "Título", 0);
}
Campos const e
readonly
Conforme
escrito no artigo, o Java
tem static final que
corresponde ao const do C#.
O campo readonly, só
presente no C# permite definir um campo que pode ser atribuído apenas
no construtor da classe e não em outros métodos. Este recurso
simplesmente não existe no Java.
Padronização
A
Microsoft submeteu no fim do ano 2000 o C# a um órgão internacional
de padronização, o ECMA (http://www.ecma.ch,
http://www.microsoft.com/NET/sharedsourcewp.asp).
A Sun fez algumas tentativas de padronizar o Java, mas nenhum órgão
internacional aceitou seus termos (http://news.cnet.com/news/0,10000,0-1003-200-320974,00.html,
http://www.cnn.com/1999/TECH/computing/12/09/java.std.cancel.idg/).
O resultado é que o Java é uma linguagem proprietária enquanto o C#
não é.
Existem
esforços para portar o C#/.NET para outras plataformas, dos quais eu
destacaria o Mono (http://lists.ximian.com/mailman/listinfo/mono-list),
PNet (http://www.southern-storm.com.au/portable_net.html)
e .NET para BSD Unix da Corel (http://www3.corel.com/cgi-bin/gx.cgi/AppLogic+FTContentServer?pagename=Corel/PressRelease/Details&id=CC100K16H9C).
Attributes
Os
attributes, um recurso
completamente inexistente em Java, permitem que você “marque” código
com informações declarativas definidas pelo programador. Estas
informações serão interrogadas em tempo de execução através de
“Reflections”.
Note
que este recurso depende do suporte a Reflection do C#, mas não está
presente no suporte a Reflection do Java.
O
resultado é algo parecido com uma diretiva de compilação definida
pelo programador. Por exemplo, para identificar um método de uma
classe como sendo chamável através de SOAP, usamos o atributo
WebMethod antes do método:
[WebMethod]
string ConsultaPedidos(int
Usuário) { ...}
O
suporte a chamadas nativas, mostrado acima, também usa attributes.
Compilado X
Interpretado
Tanto
o C# com o MSIL (Microsoft Intemediate Language) foram feitos para
serem compilados e são sempre compilados. Já o Java e o Bytecode
Java foram feitos para serem interpretados e podem ser compilados, como o artigo deixa claro. A questão “de
qual porcentagem dos programas Java são compilados” pode ser
discutida eternamente sem que se chegue a nenhuma conclusão.
Quem
quiser pesquisar as origens interpretadas do Java, pode consultar o
documento http://java.sun.com/docs/white/langenv/index.html,
de James Gosling e Henry McGilton intitulado “The Java Language
Environment”. Tal documento contém a palavra “interpreter” ou
“interpreted” mencionadas um total de 45 vezes. Veja em especial
os capítulo 1.2.5 e 5.1, dos quais tiro alguns trechos: “Em uma
plataforma interpretada como
aquelas baseadas em tecnologia Java, a fase de linkedição de um
programa é simples, incremental e leve”. “Melhores formas de
prototipação e desenvolvimento rápidos são necessárias. O
ambiente da linguagem Java é uma destas maneiras melhores, por ser interpretada
e dinâmica”. “A natureza portável e interpretada
da linguagem produz um sistema altamente dinâmico e dinamicamente
expansível”. Quem escreveu isso foi James Gosling, o pai da criança.
Quanto
a comparações entre Java Bytecode e MSIL, sugiro um artigo de uma
universidade australiana que criou compiladores Pascal tanto para Java
VM como para .NET em http://www2.fit.qut.edu.au/CompSci/PLAS//ComponentPascal/virtual_machines.pdf.
Veja alguns trechos do artigo:
“A
plataforma .NET foi explicitamente concebida para suportar múltiplas
linguagens...o caso com a JVM é menos claro, pois suporte a múltiplas
linguagens nunca foi um objetivo...existem implementações de
subconjuntos de outras linguagens, mas elas tem que superar uma série
de problemas”.
“A
comparação das duas máquinas virtuais mostra claras diferenças
entre seus objetivos de projeto. No caso da JVM, a evolução de todo
o movimento Java levou a plataforma para bem além de seu contexto
original de projeto. Tudo isto ocorreu à frente do escrutínio público
e em um contexto onde a compatibilidade com versões anteriores, a nível
de VM, quase que certamente tornou-se uma restrição custosa. Em
contraste, os projetistas da ‘VM .NET’ tiveram o luxo de postergar
decisões de congelamento do conjunto de instruções. Presumivelmente
eles também aprenderam com a experiência do Java.”
O
artigo deixa bastante claro que a MSIL, ao contrário do Java
Bytecode, foi feita para ser compilada e suportar várias linguagens.
Quem
quiser ler mais sobre compiladores e máquinas virtuais, sugiro um
artigo de Bertrand Meyer em http://www.eiffel.com/doc/manuals/technology/bmarticles/sd/dotnet.html.
Sobrecarga de
operadores
A
sobrecarga de operadores no C++ sempre foi considerada “açúcar
sintático”. Pessoalmente, tendo a concordar com a observação. No
entanto, segundo Greg DeMichillie (gerente de produto do C#) em
apresentação na qual participei, este recurso foi incluído porque o
pessoal que faz cálculos matemáticos com matrizes, vetores e números
complexos simplesmente adora a facilidade de usar notação “matemática”
ao invés de funções. Veja um possível exemplo:
class
Vetor{ . . . }
class
Matriz{ . . . }
Matriz A, B, C, Total;
Vetor V;
// Exemplo usando sobrecarga de operadores
Total = (A + B + C) * V;
// Exemplo sem sobrecarga de operadores
Total = Matriz.Produto(Matriz.Soma(Matriz.Soma(A, B), C), V);
É óbvio que a notação que usa sobrecarga de operadores é mais
simples.
Operadores de
conversão
Os
operadores de conversão no C++ são, com alguma justiça, acusados de
promover bugs ao efetuar conversões automáticas sem que o
programador tivesse planejado. Embora existam operadores de conversão
em C#, eles não sofrem dos problemas do C++. Em primeiro lugar, o
construtor que aceita um único parâmetro nunca é usado como
operador de conversão. Em segundo lugar, existem operadores implícitos,
chamados automaticamente – perigosos - e explícitos, que devem ser
chamados com sintaxe de “cast”, impedindo as conversões
inadvertidas.
Uma
nota sobre o operador de atribuição: em C#, ao contrário do C++, o
operador de atribuição não pode ser sobrecarregado, até porque
finalidade do “operator=()” em C++ era copiar VALORES e não REFERÊNCIAS.
Em C#, assim como em Java, todos os objetos são referências. A cópia
de um “valor objeto” simplesmente não é definida porque
“objetos por valor” (alocados na pilha) não são definidos.
Foreach
Este
é um recurso que sem dúvida não é essencial, mas com certeza evita
alguns bugs. O foreach um
loop usado para varrer todos os elementos de uma coleção ou array,
substituindo for ou while.
Ele evita os “famosos” problemas de loops que indexam um a mais ou
um a menos (“será que o loop começa em 0, 1 ou -1?”, “será
que o loop termina em N, N-1 ou N+1?”).
Veja
um exemplo:
// Concatena o conteúdo do ListBox em um string
string
Tudo = "";
foreach
(string Item in
listBox1.Items) {
Tudo += Item;
}
Goto
Não
estou advogando o uso de gotos
como no Applesoft BASIC ou FORTRAN. A questão tem a ver com o switch.
O
switch no C# elenca opções
mutuamente exclusivas, como no Pascal, mas mantém uma sintaxe
semelhante ao C. Por causa disto, a princípio, devemos colocar break
em todas as opções. Caso desejemos ter o mesmo comportamento do
C/C++, devemos colocar goto
de uma opção para outra.
O
resultado é que o switch
tem um comportamento mutuamente exclusivo “por default”, algo bom,
sem perder a capacidade de chamar várias opções (com goto).
Veja
um exemplo de switch em C#
usando goto:
static
string PegaTipoDoDia(string
S) {
string
Msg = "";
switch(S.ToUpper())
{
case
"SEG":
case
"TER":
case
"QUA":
case "QUI":
case
"SEX":
Msg = "Dia de semana";
break;
case
"SAB":
Msg = "Acabou
o trabalho, ";
goto
DOM;
case
"DOM":
DOM:
Msg
+= "Fim de semana";
break;
}
return
Msg;
}
Observe
que o switch pode usar
string, algo bastante útil.
Embora
o ponto sobre goto fosse
apenas um no meio de outros trinta, este é um tópico que talvez eu não
devesse ter incluído no artigo original, já que o goto tem um
“carma negativo” e este não é um assunto de muita importância.
Java na plataforma .NET
Apesar
de ter desenvolvido a linguagem C# especialmente para a plataforma
.NET, a Microsoft permite aos programadores escolher entre várias
linguagens de programação para o desenvolvimento sob .NET, inclusive
o próprio Java! Isto não é uma contradição, simplesmente quer
dizer que a escolha de linguagem é sua, não da Microsoft ou da Sun.
Você
pode obter maiores informações sobre suporte a Java na plataforma
.NET em http://msdn.microsoft.com/visualj/jump/.
Para informações sobre outras linguagens desenvollvidas fora da
Microsoft, veja em http://msdn.microsoft.com/vstudio/partners/language/default.asp.
Algumas palavras finais
Gostaria
de agradecer imensamente a comunidade de programadores Java no Brasil,
que tanto me motivou a escrever este artigo, por meio de comentários
enviados depois da publicação do artigo original.
O meu e-mail (mas_mauro@hotmail.com) está à
disposição para quem quiser fazer comentários construtivos, mesmo
que não concorde comigo.
©
Copyright 2001 por Mauro Sant’Anna – Todos os direitos reservados |