settembre 2004 Blog Posts
using System;class Outer{ class Inner { static void Main() { Console.WriteLine("Inner"); Console.Read(); } } static void Main() { Console.WriteLine("Outer"); Console.Read(); }}
Vi aspettate che:
A. scriva Inner a console;
B. scriva Outer a console;
C. non compili;
D. abbia fatto 200 post :-)
Ci vediamo domani ragazzi!
La canzone del giorno: Nick Cave & The Bad Seeds - "Babe, You Turn Me On" in cui dice:
Everything is collapsing, dearAll moral sense has goneIt's just history repeating itselfAnd babe, you turn me on
Grazie alla segnalazione del mio amico Nicola Venditti (lavora per la concorenza) vi passo questo recentissimo benchmark (pubblicato ieri!) sulla "Programming Language Popularity" fatto da David Welton. Inoltre, da non perdere David che parla nel "diaeto veneto" :-)
Questa esspressione è False:
a == a
Chi è a?
Viste le vostre ottime risposte ai test che ogni tanto vi propongo, ho deciso di premiare i migliori. Di seguito le regole per vincere e il premio:
il premio consiste nell'inserimento del vostro blog nel mio blogroll pubblico, in una sezione a parte;
per vincere è necessario avere un blog (non necessariamente su UGIdotNET!) e accettare di apparire col nome e il cognome reali;
la chiusura di un test (con il conseguente inserimento nel blogroll) avverà alla fine della settimana successiva alla data di pubblicazione del test;
l'elenco dei vincitori sarà ordinato secondo l'ordine cronologico e il...
La prima persona adulta che legge fumetti l'ho vista nel 2000, forse 2001, in metro: un po' ciccione e in giacca e cravatta, con la solita borsa in pelle tra le gambe, seduto. Nel 2000 un collega prima di andarsene via dall'azienda dove lavoravamo insieme mi regala un numero di Charlie Brown per imparare l'italiano in modo più divertente. Mi ricordo la copertina un po' rosa, la carta da giornale e il fatto che non capivo nulla, né del fumetto né del suo tenero gesto. Gli ultimi fumetti che ho letto sono stati "Luminita", "Arici Pogonici", "Licurici", "Cutezatorii" negli anni...
Michi, in questo post del 6 settembre intitolato "Reflection in disagreement with language spec" su MSDN Product Feedback Center, nota lo stesso comportamento segnalato più volte da me qui, qui e qui (e poi anche da Corrado, qui e qui)
Ecco la risposta di Chris (Microsoft), due giorni dopo:
"In general, the language spec does not need to be in agreement with the Type system. Many languages have different type systems which they then map to the CLR type system. The CLR type system is defined in the ECMA specs -- specifically ECMA Partition II specification -- not any specific language spec.
While...
Secondo il buon senso questo metodo dovrebbe ritornare sempre false. Invece ho notato con stupore che per alcuni type full name, ritorna true!
static bool IsGhostType(string typeFullName){ Type type = Type.GetType(typeFullName); if(type != null) { return !type.FullName.Equals(typeFullName); } return false;}
So che volete degli esempi :-) Eccone alcuni:
System.Object[*****] (è un System.Object[*])
System.Object[*,*,*,*,*] (è un System.Object[,,,,])
System.Object[*,,*,,*] (è un System.Object[,,,,])
La canzone del giorno: Nada - "Io l'ho fatto per amore" :-)
Quante volte questo metodo scrive "Ciao" a console?
static void Foo(bool p){ for(bool b = p; b = p; b = p) { Console.WriteLine("Ciao"); }}
A. l'esecuzione di questo metodo non scrive niente a console;
B. abbiamo un ciclo infinito;
C. non scrive nulla oppure ciclo infinito in funzione del parametro p;D. una volta.
Potete lasciare le vostre risposte nei commenti.
In questo post affermavo (in riferimento agli array unidimensionali non-vettori, cioè di limite inferiore diverso da zero) che:
"non è possibile accedere in modo indicizzato agli elementi dell'array (si devono utilizzare i metodi SetValue e GetValue)."
Lo si può fare invece tramite un ArrayList:
int lb = 100; // limite inferioreint ub = 1000; // limite superiore// int[] a = new int[lb..ub];Array a = Array.CreateInstance(typeof(int), new int[1]{ub - lb + 1}, new int[1]{lb});ArrayList al = ArrayList.Adapter(a);al[111] = 1;Console.WriteLine("al[{0}] = {1}", 111, al[111]);
Ho indagato un po' via reflection sul tipo ritornato da System.Type.GetType("System.Int32[*]").
Ha due costruttori, tutti e due instance: il primo costruttore ha un parametro int con significato di lunghezza dell'array (in questo caso il limite inferiore sarà zero!) mentre il secondo costruttore ha due parametri int: il primo parametro rappresenta il limite inferiore mentre il secondo parametro rappresenta la lunghezza meno il limite inferiore. Sono riuscito quindi a costruire un array unidimensionale non-vettore (cioè di limite inferiore diverso da zero) utilizzando System.Activator.CreateInstance (al posto di System.Array.CreateInstance).
Il codice relativo nei prossimi giorni, adesso ho un po' di fretta di andare a letto...
L'unico modo che ho trovato possibile per utilizzare gli array unidimensionali di limite inferiore diverso da zero è questo che risulta dal seguente snippet:
int lb = 100; // limite inferioreint ub = 1000; // limite superiore// int[] a = new int[lb..ub];Array a = Array.CreateInstance(typeof(int), new int[1]{ub - lb + 1}, new int[1]{lb});// a[111] = 1;a.SetValue(1, 111);Console.WriteLine("a[{0}] = {1}", 111, a.GetValue(111));
Si può verificare che:
il tipo di a è System.Int32[*] (ancora non ho capito bene il significato dell'asterisco che appare solo nel caso di un array unidimensionale creato con System.Array.CreateInstance e con il limite inferiore diverso da zero);
gli array unidimensionali col limite...
Posso creare array MULTIdimensionali con un limite inferiore diverso da zero; lo spiega Richter nel suo libro alla pagina 318 e poi con un copia e incolla dello stesso esempio in SLAR alla pagina 49.
Ma se voglio "estrapolare" lo stesso metodo per un array UNIdimensionale in una sintassi immaginaria:
int[] a = new int[lb..ub]; // questa sintassi non è ancora implementata!
dove lb è lower bound (per esempio 100) e ub è upper bound (per esempio 1000), scrivere:
int[] a;// dichiarare e inizializzare lb e ub...a = (int[])Array.CreateInstance(typeof(int), new int[1]{ub - lb + 1}, new int[1]{lb});
dà a run-time l'errore System.InvalidCastException ("Specified cast is...
In questo elenco sul mail server del Dipartimento di Informatica dell'Università di Pisa, troverete una serie di mailing list, alcune dedicate a .NET e di un livello che il nome di Pisa vi garantisce sempre.
Si sa che possiamo creare array con lower bound non zero, quindi è possibile avere un elemento a[..., i, ...] con i > a.Length. Mi sono chiesto allora quale sia il valore massimo che GetLowerBound e GetUpperBound possono restituire. Mi aspettavo che fosse int.MaxValue, invece per un lower bound int.MaxValue e un length 1 per una certa dimensione otteniamo System.ArgumentOutOfRangeException con il messaggio "Higher indices will exceed Int32.MaxValue because of large lower bound and/or length". Per fare il pignolo, nel nostro caso non abbiamo alcun "higher index" (la lunghezza è 1). Come mai l'errore?
Non si tratta di un test ma...
Al mio "Test (un'equazione in C#)", Michele Bernardi ha suggerito una soluzione che contiene però un errore diciamo "interessante". Per aiutarvi, ecco la frase sbagliata: "1 bit per il segno, 10 per l'esponente e 53 per la mantissa" che, secondo lo standard IEEE 754 dovrebbe essere così: "1 bit per il segno, 11 bit per l'esponente e 52 per la parte frazionaria". Come mai allora il risultato rimane 1023 = Pow(2, 10) - 1, come già indovinato da Gianluca per primo?
Il test continua :-)
La canzone del giorno: Patty Pravo - "Morire... Dormire... Forse sognare...".
Se nel vostro assembly di test (NUnit) avete un file "App.config", dovete copiare questa riga esattamente così com'è, senza sostituire nulla:
copy "$(ProjectDir)app.config" "$(TargetDir)$(TargetFileName).config"
e incollarla in:
Common Properties > Build Events > General > Post-build Event Command Line
sotto le proprietà del vostro progetto di test.
Utilissimissimo tip se implementate per esempio il pattern Provider (come sto facendo io). Qualcuno conosce un'altra soluzione?
Si chiede il valore minimo dell'intero positivo n per avere la seguente espressione True:
long.MaxValue - n - (long)(double)(long.MaxValue - n) == 0
Le soluzioni con le necessarie spiegazioni postatele nei commenti di questo post. Proponete voi la data di chiusura del test, sempre nei commenti.
In C#, "integer literals have two possible forms: decimal and hexadecimal" (9.4.4.2) ma in Java "an integer literal may be expressed in decimal, hexadecimal, or octal" (3.10.1).
Per questo, 08 in C# è 8, mentre in Java si ottiene errore di compilazione "integer number too large" (il prefisso del literal di un intero in base 8 in Java è 0).
Post da ragazzini, lo so, però l'ho postato per distanziarmi da Corrado solo di 99 post... :-)
Un'eccellente introduzione a MSIL scritta da Kenny Kerr in una serie di post. Per stimolarvi l'appetito, qualche spunto:
"Unlike C#, CLI does not have any requirement that a method must belong to a class."
"It is also possible to omit the variable names. In that case you would refer to the variables by their zero-based index in the declaration."
"You must declare a constructor for a concrete reference type. Unlike languages like C# and C++, the IL assembler will not generate a constructor for you automatically."
"The CLI does not recognize namespaces as a distinct concept. Rather the full type name is always used."
"If...
Ieri Giancarlo mi ha chiesto via mail:
"Ho sempre avuto un dubbio... Perchè nella definizione di una interfaccia non c'è la possibilità di specificare anche una firma per eventuali costruttori?"
Gli rispondo qui per togliere eventualmente anche ad altri lo stesso dubbio.
Partiamo da Richter, p. 326 (come si deve):
"Il linguaggio CLR consente alle interfacce di contenere costruttori static.CLR non consente alle interfacce di contenere alcun costruttore di istanza."
e da questo banale snippet "Foo.cs":
interface IFoo{void NonUnCostruttore();}
Lo compiliamo:
csc /t:library Foo.cs
per ottenere il codice IL:
ildasm Foo.dll /out=Foo.il
Il metodo NonUnCostruttore avrà questa dichiarazione in IL:
.method public hidebysig newslot abstract virtual instance void NonUnCostruttore() cil managed
Con l'aiuto...
Ieri sera, dopo il post di Corrado, ho continuato a giocare un po' con le interfacce perché è venuto anche a me il dubbio di un possibile bug di IsSubclassOf... E lo snippet sotto lo dimostra:
using System;using System.Reflection;interface IFoo{}public class Foo{ static void Main() { BindingFlags all = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; Type ifooType = typeof(IFoo); Type objectType = typeof(object); Console.WriteLine("{0} is{1} subclass of {2}", ifooType.Name, ifooType.IsSubclassOf(objectType) ? "" : "'nt", objectType.Name); Console.WriteLine("{0}\t#members = {1}", ifooType.Name, ifooType.GetMembers(all).Length); Console.WriteLine("{0}\t#members = {1}", objectType.Name, objectType.GetMembers(all).Length); Console.Read(); }}
L'output è questo:
IFoo is subclass of ObjectIFoo #members = 0Object #members = 14
Però, se IFoo fosse veramente "subclass" di Object, avremmo dovuto...
Il mio primo post, dopo quello di presentazione, è stato su "L'asimmetria dell'ISerializable", seguito a brevissima distanza da un altro sullo stesso argomento: "Prima ISerializable aveva SetObjectData". Stamattina sul treno, vedo che anche Juval Lowy (Regional Director, Software Legend), nel suo libro "Programming .NET Components", alla pagina 224, scrive:
"The design decision the architects of .NET serialization took was to force a runtime check for the deserialization constructor instead of a compile-time check. However, I believe a better design decision would have been to provide a SetObjectData() method on ISerializable and, during deserialization, use reflection to set the fields of a...
I numeri possibili nel Quiz Sharp #36 sono:
1 - Pow(10, -2043)
e
0 = 0 * Pow(10, Pow(10, 2043) - 1)
Per avere un'idea sulla grandezza del numero moltiplicato con 0, pensate che un googolplex è "solo" Pow(10, Pow(10, 100)).
Se al posto di 0 mettete 1, cioè 1e99...9, ovviamente il compilatore vi dà "Floating-point constant is outside the range of type 'double'". Come mai allora per 0e99...9 va tutto bene e il compilatore fornisce il risultato corretto? Il compilatore riconosce una moltiplicazione con 0 e chiude per il resto gli occhi. Quando tokenizza la parte exponent dell'espressione 0e99...9, non gli interessa di rappresentare...
Se dobbiamo sostituire il punto di domanda con un unico carattere, quante soluzioni valide (senza errori o warning) esistono? (in quella riga si trovano 2043 cifre 9 consecutive)
class Foo{ static void Main() { System.Console.WriteLine (0?99...9 ); }}
A. 1;
B. 2;
C. 3.
Potete lasciare le vostre risposte nei commenti.
Cosa dobbiamo mettere al posto del punto di domanda (sono permessi anche più caratteri), per rendere valido il seguente snippet?
class Foo{ static void Main() { System.Console.WriteLine(-?-); }}
Apprezzerò, come sempre, le spiegazioni migliori. Se non si vede bene nell'HTML, il punto di domanda è delimitato da due trattini che devono rimanere così.
Cosa ne dite di lasciare le vostre soluzioni e soprattutto spiegazioni nei commenti al posto di mandarmeli in mail? E' vero che si potrebbe perdere un po' della tensione della sfida, però da un'altra parte avreste un confronto più diretto e immediato tra di voi. E poi la gara secondo me migliorerebbe in qualità...
Il test di buon rientro, di cui vi ho svelato ieri sera i vincitori (purtroppo solo due) con le loro soluzioni, ha, come vi ho già accennato, comportamenti e spegazioni diversi in C# rispetto a Java. In un commento, Flavio mi ha chiesto come stanno le cose in Java - magari anche altri hanno la stessa curiosità (il confronto fra C# e Java fa, secondo me, sempre bene).
Mary Smaragdis, una dipendente di Sun, ospita nel suo blog un simpatico concorso di quiz chiamato "Friday Free Stuff" con piccoli premi sponsorizzati dalla sua tenera generosità - eh sì, qui siamo diversi......
Ormai sono passate quasi due settimane da quando vi ho proposto questo test:
"Pensate a dichiarare e inizializzare x e y in modo da avere:
x += y; // un'assegnazione correttax = x + y; // errore di compilazione"
e aggiungevo che "apprezzerò nei vostri feedback le spiegazioni migliori". Alla fine, siete ri-entrati tutti (dalle vacanze) ma solo due di voi sono ri-usciti :-) a mandarmi feedback validi.
Il primo è stato lo Schumacher dei miei test, Flavio Polesello:
"Per generare un errore di compilazione sull'assegnazione x = x + y è sufficiente dichiarare le variabili x e y di 1 o di 2...
Vi ricordate i miei punti di domanda sul null type? (qui,
qui
e qui)
Per forzare il compilatore a dire di più, ho scritto una follia del
genere:bool b = null.Equals(null, null)
e il compilatore ha risposto coll'errore CS0023:
"Operator '.' cannot be applied to operand of type '<null>'".
Non trovate niente di strano? "of type '<null>'" e non
"of type 'null'"!
Cosa dobbiamo capire? Che il nome del null type è "<null>"?
Tutti sanno del nesting separator (il segno "+") nel fully qualified name di una classe (in italiano come si dice?
nome completo?).
Ma non tutti sanno che il segno "+" può comparire anche all'interno
del nome di un namespace. Non in C#, però in IL sì.
Giochiamo un po':
// Foo.csnamespaceA.BC
{
class D{}
}
Compiliamo il codice C# con:
csc /target:library Foo.cs
otteniamo il codice IL:
ildasm Foo.dll /out=Foo.il
e in tutte e due le sezioni "CLASS STRUCTURE DECLARATION" e "CLASS MEMBERS DECLARATION"
la dichiarazione del namespace la cambiamo da:
.namespace A.BC
a:
.namespace 'A.B+C'
e poi compiliamo il codice IL con:
ilasm /DLL Foo.il
Sorpresi del messaggio "Operation completed successfully"?
Adesso il nome completo della classe...