Revista programar 26

1.549 visualizações

Publicada em

Publicada em: Tecnologia
0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
1.549
No SlideShare
0
A partir de incorporações
0
Número de incorporações
2
Ações
Compartilhamentos
0
Downloads
29
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Revista programar 26

  1. 1. EditorialEDITORIAL EQUIPA PROGRAMAR Sempre em movimento… Coordenadores Porque sabemos que parar é morrer, nesta edição da Revista António Silva PROGRAMAR introduzimos várias alterações que achamos importantes Fernando Martins para continuidade deste projecto. Das várias alterações introduzidas, a salta imediatamente à vista, mesmo ao leitor que ainda está somente a ler a Editor página do editorial, é a mudança de design . Em qualquer tipo de António Silva publicação o design influencia o modo como vemos como lemos. Aqui temos que agradecer a todos quantos ajudaram a adaptar este novo design, Design mas especialmente ao Sérgio Alves por toda a parte da idealização e Sérgio Alves (@scorpion_blood) desenho do novo design. Outra alteração, que todavia não será tão notada pelos leitores é a Redacção alteração do software de paginação. Chegamos à conclusão que o Scribus André Lage, Augusto Manzano, Diogo já evoluiu bastante desde a última vez que foi utilizado para paginar a Constantino, Fernando Martins, João Mares, Revista PROGRAMAR e está à altura das nossas necessidades. Assim João Matos, Jorge Paulino, Paulo Morgado, decidimos que não havia necessidade de continuarmos a utilizar um Pedro Aniceto, Ricardo Rodrigues, Ricardo software pago e que trazia vários problemas de leitura a alguns utilizadores Trindade, Sara Silva (dos quais chegamos a receber comentários). Também fizemos várias parcerias com algumas comunidades Contacto portuguesas que estão de algum modo relacionadas com programação, de revistaprogramar@portugal-a-programar.info modo a obter mais e melhores artigos para si. Todavia não estamos fechados a mais parcerias, continuamos abertos a futuros contactos para o Website nosso endereço de correio electrónico, que serão posteriormente analisados http://www.revista-programar.info por toda a equipa. Trazemos também até si, colunas de opinião e colunas direccionadas a ISSN um tema específico. Assim poderá contar que surgirão artigos desse 1 647-071 0 assunto com uma periodicidade específica na sua Revista favorita. Por fim, achamos que estamos prontos para voltar a trazer a Revista PROGRAMAR até si de 2 em 2 meses , e por isso a próxima edição deverá INDICE sair em Fevereiro ao invés de Março como estava programado.4 Tema de Capa - LINQ Tudo isto para si, que está ler. Esperámos que as alterações sejam bem11 BYACC recebidas por todos, mas também esperámos opiniões sobre todas estas18 Introdução ao Entity Framework alterações, mesmo porque as novidades poderão não ficar por aqui,23 Programação Funcional Perl (Parte I ) contámos ter mais novidades na próxima edição. Por isso não tenha medo26 BackgroundWorkers em WPF de nos contactar para revistaprogramar@portugal-a-programar.org a dizer o31 jQuery - O quê, como e porquê? que acha de todas estas alterações. Porque você é importante para nós,35 Tutorial de Lua (Parte 6) quer as suas opiniões, quer o seu trabalho a divulgar o nosso projecto aos41 E se amanhã a Apple dominar? seus amigos e colegas, e mais importante a sua preferência que nos43 SQL em Oracle permite crescer para lhe oferecer algo maior e melhor.47 Aspectos low-level de 3D54 Quando se é ! Produtivo A equipa da Revista PROGRAMAR56 Client Object Model para SilverlightA revista PROGRAMAR é um projecto voluntário, sem fins lucrativos. Todos os artigos são da responsabilidade dos autores, não podendo a revista ou acomunidade ser responsabilizada por alguma imprecisão ou erro. Para qualquer dúvida ou esclarecimento poderá sempre contactar-nos. 2
  2. 2. Noticias NOTICIAS U p l o a d Li s b o a e U p l o a d Li s b o a Se m i n á ri o Po c ke tPT s o b re Pro 2 0 1 0 te c n o l o gi a s Wi n d o ws Ph o n eO Upload Lisboa é um evento que por si só nomeia a era Encontram-se abertas as inscrições para o 6º Seminárioem que estamos. A era da nova comunicação, da troca de PocketPT sobre tecnologias móveis Windows Phone. Esteinformação no momento, de forma prática e natural, e da ano o seminário será dedicado à nova plataforma móvel dapartilha de conhecimentos em rede. O Upload Lisboa Microsoft, e irá incluir várias sessões que irão dar apretende, mais uma vez, passar a esfera da rede interior e conhecer as funcionalidades do mesmo.global para a esfera da partilha conjunta, física. Será ainda uma excelente oportunidade para osEste evento nasce da necessidade crescente de debate e participantes testarem e verem em primeira mão os novospartilha de conhecimentos sobre a web 2.0, numa altura em equipamentos.que as novas plataformas de comunicação e informação Como tem vindo a acontecer nos anos anteriores aassumem um lugar cada vez mais central na vida de inscrição este ano é gratuita e irá ter lugar no auditório dapessoas e empresas. Hoje, mais que nunca, a partilha Microsoft Portugal no TagusPark em Porto Salvo noatravés das plataformas sociais na web ocupam um lugar próximo dia 1 8 de Dezembro pelas 1 0h.de destaque na influência na opinião pública e na formação Mais informações e inscrições:de critérios de análise ao que se passa no país e no http://www.mtechseminar.com/201 0/index.htmmundo.São dois dias, 11 e 1 5 de Dezembro, que certamente nãoirá perder!Mais informações: http://uploadlisboa.com/ SAPO C o d e B i ts 2 0 1 0 1 6 a R e u n i ã o Pre s e n c i a l d a C o m u n i d a d e N e tPo n toDe 11 a 1 3 de Novembro de 201 0 decorreu o Sapo No dia 11 /1 2/201 0 será realizada a 1 6ª reunião presencialCodebits 201 0. A comunidade Portugal-a-Programar esteve da comunidade NetPonto, em Lisboa. Nesta sessão,presente, tendo alguns membros efectuado alguns poderá ver duas apresentações presenciais sobre Domainprojectos. Este ano, com oferta da comunidade, todos os Driven Design e WP7 & XNA – Let’s play?que participaram e solicitaram, tiveram direito a uma t-shirt Para participar, basta efectuar a inscrição através do sitepara usar durante o evento. http://netponto-lisboa-dezembro-201 0.eventbrite.com/ AEsta foi a foto de grupo de alguns dos elementos que entrada é gratuita e são realizadas reuniões todos osestiveram presentes (infelizmente não foi possível juntar meses.todos): Para mais informações, consulta de próximas sessões e inscrição: http://netponto.org/ 3
  3. 3. TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st,Ta ke La stWh i l e , Ski p La st e S ki p La stWh i l eHá algum tempo necessitei de obter os últimos original uma vez e mais três vezes sobre ositens de uma sequência que satisfaziam um itens que satisfazem o critério. Se a sequênciadeterminado critério e, olhando para os original for grande, isto pode consumir muitaoperadores disponíveis na classe Enumerable, memória e tempo.apercebi-me de que tal operador não existia. Existe ainda um problema adicional quando seA única forma de obter o resultado pretendido usa a variante que usa o índice de item naera inverter a ordem dos itens na sequência, sequência original na avaliação do critério deobter os itens que satisfaziam o critério e inverter selecção (>). Quando se inverte a ordem dosos itens da sequência resultante. itens, os índices destes serão invertidos e o predicado de avaliação do critério de selecçãoAlgo como isto: terá de ter isso em consideração, o que poderá não ser possível se não se souber o número de Sequence itens na sequência original. .Reverse() .TakeWhile(criteria) Tinha de haver uma solução melhor, e é por isso .Reverse(); que eu implementei os Operadores Take Last: TakeLast<TSource>(IEnumerable<TSource>)Parece simples, certo? Primeiro chamamos ométodo Reverse para produzir uma nova Retorna o número especificado de elementossequência com os mesmos itens mas na ordem contínuos no fim da sequência.inversa da sequência original, depois chamamos int[] grades = { 59, 82, 70, 56, 92, 98, 85o método TakeWhile para obter os primeiros };itens que satisfazem o critério e, finalmente,chamamos novamente o método Reverse para var topThreeGrades = gradesrecuperar a ordem original dos itens. .OrderBy(grade => grade) .TakeLast(3);O problema desta aproximação é que o métodorev memoriza toda a sequência antes de iterar Console.WriteLine("As notas mais altassobre os seus itens na ordem inversa – e o são:");código acima usa-o duas vezes. Isto significaiterar sobre todos os itens da sequência original foreach (int grade in topThreeGrades)e memoriza-los, iterar sobre os primeiros itens {que satisfazem o critério e memoriza-los e, Console.WriteLine(grade);finalmente, iterar sobre estes itens para produzir }a sequência final.Se estiveram a contar, chegaram à conclusão deque se iterou sobre todos os itens da sequência 4
  4. 4. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e /* string[] fruits = Este código produz o seguinte resultado: { "maçã", "maracujá","banana", "manga", As notas mais altas são: "laranja", "mirtilo", "uva", "morango" }; 98 var query = fruits 92 .TakeLastWhile((fruit, index) => 85 fruit.Length >= index); */ foreach (string fruit in query)TakeLastWhile<TSource>(IEnumerable<TSou {rce>, Func<TSource, Boolean>) Console.WriteLine(fruit); }Retorna os elementos do fim da sequência paraos quais a condição especificada é verdadeira. /* Este código produz o seguinte resultado: string[] fruits = morango { "maçã", "maracujá","banana", "manga", */ "laranja", "mirtilo", "uva", "morango" }; Tendo introduzido os operadores TakeLast, faz var query = fruits todo o sentido introduzido os seus duais: os .TakeLastWhile(fruit => operadores SkipLast: string.Compare("laranja", fruit, true) != 0); SkipLast<TSource>(IEnumerable<TSource>) foreach (string fruit in query) Retorna todos os elementos da sequência à { excepção do número especificado de elementos Console.WriteLine(fruit); contínuos no fim da sequência. } int[] grades = /* { 59, 82, 70, 56, 92, 98, 85 }; Este código produz o seguinte resultado: var lowerGrades = grades maracujá .OrderBy(g => g) uva .SkipLast(3); morango */ Console.WriteLine("Todas as notas excepto as top 3:");TakeLastWhile<TSource>(IEnumerable<TSou foreach (int grade in lowerGrades)rce>, Func<TSource, Int32, Boolean>) { Console.WriteLine(grade);Retorna os elementos do fim da sequência para }os quais a condição especificada é verdadeira. 5
  5. 5. TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e /* SkipLastWhile<TSource>(IEnumerable<TSour Este código produz o seguinte resultado: ce>, Func<TSource, Int32, Boolean>) As notas mais altas, excepto: 56 Retorna todos os elementos da sequência à 59 excepção dos elementos do fim da sequência 70 para os quais a condição especificada é 82 verdadeira. */ int[] amounts = {SkipLastWhile<TSource>(IEnumerable<TSour 5000, 2500, 9000, 8000,ce>, Func<TSource, Boolean>) 6500, 4000, 1500, 5500 };Retorna todos os elementos da sequência àexcepção dos elementos do fim da sequência var query = amountspara os quais a condição especificada é .SkipWhile((amount, index) => amount >verdadeira. index * 1000); int[] grades = foreach (int amount in query) { 59, 82, 70, 56, 92, 98, 85 }; { var lowerGrades = grades Console.WriteLine(amount); .OrderBy(grade => grade) } .SkipLastWhile(grade => grade >= 80); /* Este código produz o seguinte resultado: Console.WriteLine("Todas as notas menores que 5000 80:"); 2500 */ foreach (int grade in lowerGrades) { Console.WriteLine(grade); } IMPLEMENTADO OS OPERADORES TAKELAST /* I mplementando O Operador TakeLast Este código produz o seguinte resultado: Todas as notas menores que 80: O operador TakeLast retorna o número 56 especificado de elementos contínuos do fim de 59 uma sequência e é implementado como o 70 método de extensão TakeLast. */ Para implementar este operador, primeiro começamos por memorizar, pelo menos, o número requerido (count) de itens da sequência 6
  6. 6. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l efonte (source) num array que funciona como for (; numOfItems > 0; idx = (idx + 1) %uma memória intermédia (buffer) circular: count, numOfItems--) var sourceEnumerator = { source.GetEnumerator(); yield return buffer[idx]; var buffer = new TSource[count]; } var numOfItems = 0; int idx; Há duas optimizações que ainda podemos fazer. for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++, A primeira é óbvia, se o número de itens numOfItems++) requerido for 0 (zero), retornamos uma { sequência vazia: buffer[idx] = sourceEnumerator.Current; if (count <= 0) {Se o número de itens memorizados return(numOfItems) for inferior ao número requerido System.Linq.Enumerable.Empty<TSource>();(count), produzimos os itens memorizados: } if (numOfItems < count) A segunda é se a sequência fonte (source) { implementar a interface IList<T>. Os objectos for (idx = 0; idx < numOfItems; idx++) que implementam esta interface têm uma { propriedade Count e acesso indexado aos seus yield return buffer[idx]; itens que nos permite optimizar a produção da } sequência final. yield break; } A produção da sequência final passa por produzir o número de itens requeridos do fim daEm seguida, iteramos pelos restantes itens e lista (ou todos se a lista contiver menos que osvamos os armazenando, de forma circular, na itens requeridos):memória intermédia: int listCount = list.Count; for (idx = 0; sourceEnumerator.MoveNext(); for (int idx = listCount - ((count < idx = (idx + 1) % count) listCount) ? count : listCount); idx < { listCount; idx++) buffer[idx] = { sourceEnumerator.Current; yield return list[idx]; } } Implementando os OperadoresE finalmente, iteramos sobre os itens TakeLastWhilememorizados para produzir a sequência final: O operador TakeLastWhile retorna os últimos 7
  7. 7. TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l eelementos contíguos que satisfazem o critério buffer.Add(item);especificado e é implementado como os }métodos de extensão TakeLastWhile. elsePara implementar este operador, primeiro {começamos com uma memória intermédia buffer.Clear();(buffer) vazia e, para cada item que satisfaça o }critério implementado pelo predicado (predicate), }memorizamos esse item. Sempre que ocorrerum item que não satisfaça o critério de selecção, foreach (var item in buffer)a memória intermédia é limpa: { var buffer = new List<TSource>(); yield return item; foreach (var item in source) } { if (predicate(item)) { IMPLEMENTANDO OS OPERADORES buffer.Add(item); SKIPLAST } else Implementando o Operador SkipLast { buffer.Clear(); O operador SkipLast retorna o número } especificado de elementos contínuos do fim de } uma sequência e é implementado como o método de extensão SkipLast.Depois de percorrer toda a sequência fonte Para implementar este operador, começamos(source), produzimos todos os itens, se por memorizar, pelo menos, o número requeridoexistirem, da memória intermédia: (count) de itens da sequência fonte (source) num array que funciona como uma memória foreach (var item in buffer) intermédia (buffer) circular: { yield return item; var sourceEnumerator = } source.GetEnumerator(); var buffer = new TSource[count];A diferença para o método que tem em conta o int idx;índice do item no predicado (predicate) deselecção é apenas na invocação deste: for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++) var buffer = new List<TSource>(); { var idx = 0; buffer[idx] = sourceEnumerator.Current; } foreach (var item in source) { Em seguida, iteramos pelos restantes itens da if (predicate(item, idx++)) sequência fonte (source) memorizando { 8
  8. 8. TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l ecircularmente cada item e produzindo o item var list = source as IList<TSource>;armazenado anteriormente na mesma posição: if (list != null) idx = 0; { if (count >= list.Count) while (sourceEnumerator.MoveNext()) { { return var item = buffer[idx]; System.Linq.Enumerable.Empty<TSource>(); buffer[idx] = sourceEnumerator.Current; } idx = (idx + 1) % count; // ... } yield return item; } Se o número de itens da sequência fonte (source) for superior ao número de itens aSe o número de itens a excluir for igual ou excluir, produzir a sequência final consiste emsuperior ao número de itens existentes na produzir todos os itens da sequência fontesequência fonte (source), o método (source) excepto os últimos count itens:sourceEnumerator.MoveNext() retornará false naprimeira iteração do ciclo while e será produzida int returnCount = list.Count - count;uma sequência vazia. for (int idx = 0; idx < returnCount; idx++)Tal como acontecia com o operador TakeLast, {podem-se fazer algumas optimizações. yield return list[idx]; }A primeira é óbvia, se o número de itensrequeridos for 0 (zero) ou inferior, retornamos Implementando os Operadoresuma sequência equivalente à fonte (source): SkipLastWhile if (count <= 0) O operador SkipLastWhile retorna os últimos { elementos contíguos que satisfazem o critério return source.Select(i => i); especificado e é implementado como os } métodos de extensão SkipLastWhile. Para implementar este operador, primeiroA segunda é se a sequência fonte (source) começamos com uma memória intermédiaimplementar a interface IList<T>. Os objectos (buffer) vazia e, para cada item que satisfaça oque implementam esta interface têm uma critério implementado pelo predicado (predicate),propriedade Count e acesso indexado aos seus memorizamos esse item.itens que nos permite optimizar a produção dasequência final. Sempre que ocorrer um item que não satisfaça o critério de selecção, a memória intermédia éSe o número de itens a excluir for igual ou limpa e o item que não satisfaz o critério ésuperior ao número de itens da sequência fonte produzido:(source), retornamos uma sequência vazia: 9
  9. 9. TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e var buffer = new List<TSource>(); else foreach (var item in source) { { if (buffer.Count > 0) if (predicate(item)) { { foreach (var bufferedItem in buffer) buffer.Add(item); { } yield return bufferedItem; else } { buffer.Clear(); if (buffer.Count > 0) } { yield return item; foreach (var bufferedItem in buffer) } { } yield return bufferedItem; } buffer.Clear(); Conclusão } Como podem ver, implementar este tipo de yield return item; operadores é muito fácil, pelo que, não se deve } evitar a sua implementação sempre que se } justifique. Implementar um específico para a nossa aplicação pode significar uma melhorA diferença para o método que tem em conta o legibilidade do código e até um aumento deíndice do item no predicado (predicate) de performance.selecção é apenas na invocação deste: Podem encontrar a implementação completa destes operadores (e outros) no meu projecto de var buffer = new List<TSource>(); utilitários e operadores para LINQ no CodePlex: var idx = 0; PauloMorgado.Linq. foreach (var item in source) Recursos { O meu website: http://PauloMorgado.NET/ if (predicate(item, idx++)) Livro “LINQ Com C#” { PauloMorgado.Linq buffer.Add(item); Classe Enumerable } Métodos de extensão AUTOR Escrito por Paulo Morgado É licenciado em Engenharia Electrónica e Telecomunicações (Sistemas Digitais) pelo Instituto Superior de Engenharia de Lisboa e Licenciado em Engenharia Informática pela Faculdade de Ciências e Tecnologia da Universidade Nova de Lisboa. Pelo seu contributo para a comunidade de desenvolvimento em .NET em língua Portuguesa, a Microsoft premeia-o com o prémio MVP (C#) desde 2003. É ainda co-autor do livro “LINQ Com C#” da FCA. 10
  10. 10. A PROGRAMARBYAC CNo artigo anterior adquirimos algumas noções eles seguem a gramática que ele define. Se osobre flex e vimos como implementar um objectivo do parser for só verificar que um certoscanner simples. Relembrando, o flex é um ficheiro, por exemplo um ficheiro xml, segue agerador de analisadores lexicais ou scanners, e especificação da linguagem, podemos não tero byacc é um gerador de parsers. Usados em interesse nenhum em saber o valor de qualquerconjunto permitem escrever aplicações bastante token. A nossa calculadora no entanto, precisasofisticadas, mas no nosso artigo limitamo-nos a de produzir resultados, portanto necessita deconsiderar uma calculadora simples, servindo saber o valor de cada token NUMBER quecomo exemplo introdutório. Agora que temos o recebe. O parser define os tokens e o tipo descanner para a nossa calculadora escrito valores que lhes podem estar associados napodemos começar a considerar o parser. zona das definições, sempre que precisa de um token novo ele chama o scanner com o resto doUm ficheiro byacc tem a mesma estrutura que o input que falta analisar. Vejamos a definição dosflex, já que o analisador lexical em que o flex se tokens para a nossa calculadora:baseia, o lex, copiou a sua estrutura do yacc, ogerador de parsers em que o byacc se baseia. %union {Como tal o nosso ficheiro byacc vai ser algo double d;deste género: }; definições %token<d> NUMBER %token NL %% %left + - gramática %left * / %right ^ %% %nonassoc UMINUS int main() { %% yyparse(); } ... %%Comecemos por considerar como é que o parsere o scanner funcionam em conjunto. Um parser int main()recebe tokens e verifica se esses tokens estão a {seguir uma gramática. O que nós estávamos a yyparse();retornar no scanner, o NUMBER e o NL são }esses tokens. Os tokens podem ter um valorassociado ou não. O que o parser faz é ver se 11
  11. 11. A PROGRAMARBYAC CA primeira coisa que encontramos é uma%union, seguida da declaração de dois tokens, %%NUMBER e NL. A %union serve para indicar expr_list : expr NL { std::couttipos que queiramos associar a tokens e << $1 << std::endl; }eventualmente a elementos da gramática. Ao | expr_list expr NL {escrevermos %token<d> NUMBER estamos a std::cout << $2 << std::endl; }indicar que para além de NUMBER ser um ;token, tem um valor associado do tipo d, nestecaso double. Isto vai ser importante quando expr : NUMBER { $$ = $1; }passarmos para a gramática e é por esta razão | - expr %prec UMINUS { $$ =que no scanner passávamos o número que -$2; }tínhamos lido ao yylval.d antes de retornarmos o | expr + expr { $$ =token. A informação da union e dos tokens que $1+$3; }escrevermos nesta secção vai servir para o | expr - expr { $$ = $1-byacc gerar o header ao qual o nosso scanner $3; }fez #include e que permite ao scanner e ao | expr * expr { $$ =parser comunicarem entre si. O +, -, *, /, ^ e $1*$3; }UMINUS também são tokens mas aqui para | expr / expr { $$ =além de indicarmos que são tokens estamos a $1/$3; }indicar a associatividade dos operadores, um | expr ^ expr { $$ =conceito que o leitor deverá conhecer, mas que pow($1, $3); }abordaremos com maior profundidade na | ( expr ) { $$ = $2;gramática. } ; %{ #include <iostream> #include <cmath> %% %} int main() { %union { yyparse(); double d; } }; Esta versão do parser introduz a gramática, mas %token<d> NUMBER comecemos por observar as diferenças na %token NL secção das definições. Podemos ver primeiro que a introdução de código C/C++ se processa %left + - da mesma forma que no scanner. Em seguida %left * / temos a instrução, %type<d> expr, expr não é %right ^ um token, é outro símbolo da gramática mas %nonassoc UMINUS ainda assim tem um tipo, portanto temos que o indicar. %type<d> expr Uma gramática, tal como a gramática da língua 12
  12. 12. A PROGRAMAR BYAC Cportuguesa, serve para nos indicar a estrutura faz sentido criar várias produções para um stmt,da linguagem, quais as composições de já que um stmt pode ser várias coisas. Nesteelementos que são válidas ou não de acordo caso, um while, um if, um bloco, e continuandocom a linguagem. É fácil de ver como isto é útil teríamos um for, um switch, um do while, etc.para um compilador. A nossa calculadora tem Sendo usual a existência de várias produçõesuma gramática muito simples, mas ainda assim com a mesma cabeça, o byacc permite usar atem-la, portanto temos que compreender alguns seguinte sintaxe, com significado equivalente,princípios sobre gramáticas. As gramáticas são para aumentar a legibilidade:um conjunto de regras, às quais chamamos stmt : WHILE expression stmtproduções, constituídas por uma cabeça e um | IF expression stmtcorpo. Por exemplo, | IF expression stmt ELSE stmt | block stmt : WHILE expression stmt; ... ;é uma produção, com cabeça stmt e corpoWHILE expression stmt. A cabeça indica-nos Se quiséssemos escrever um parser para umauma construção da gramática e o corpo como linguagem de programação, tínhamos de terela é composta. Os elementos duma gramática uma forma de relacionar as várias regras, pordividem-se em símbolos terminais e não outras palavras uma gramática necessita determinais, sendo os terminais, para efeitos deste uma estrutura. A forma de criar essa estrutura éartigo, os tokens que o scanner envia e os não- criando um símbolo não terminal inicial ao qualterminais as cabeças de produções, ou seja todos os outros estão subordinados. Pode ajudarsímbolos que podem ser produzidos através pensar na estrutura da gramática como umadoutros símbolos. árvore na qual o símbolo não terminal inicial é a raiz, os outros não terminais são nós e osPor clareza, usamos maiúsculas para terminais são as folhas.representar terminais e minúsculas para nãoterminais, logo, no exemplo acima, stmt e %%expression são símbolos não terminais enquantoque o WHILE é terminal. Um símbolo terminal program : listnão pode ser obtido através da junção de outros ;símbolos, portanto só pode aparecer em corposde produções. Um não terminal por outro lado list : statementpode ser derivado de terminais e outros não | list statementterminais, logo pode aparecer tanto na cabeça ;como no corpo duma produção. Um símbolo nãoterminal pode, e habitualmente, tem várias statement : declarationdefinições. Pegando no exemplo anterior e | functionexpandindo, obtemos, ; stmt : WHILE expression stmt; declaration : type identifier stmt : IF expression stmt; | type identifier = stmt : IF expression stmt ELSE stmt; expression stmt : block; ; ... 13
  13. 13. A PROGRAMARBYAC C s : x | y type : INT ; | DOUBLE x : A B C ; | CHAR y : A B C ; ; Este caso é óbvio, temos duas produções function : type identifier ( arg_list ) diferentes com o mesmo corpo, o parser não block sabe qual deve usar quando recebe os três ; tokens. O mesmo se passa nos casos seguintes. block : { stmt_list } s : x ; | y ; stmt_list : stmt x : A B C ; | stmt_list stmt y : A z C ; ; z : B ; ... %% s : x | yAcima temos um esqueleto de uma linguagem ;muito simplificada, ainda com vários não x : A B C ;terminais sem produções associadas, mas basta y : z C ;para termos uma noção da estrutura duma z : A B ;gramática. Qualquer que seja o programa escritopara esta linguagem, se ele estiver O byacc só tem um token de lookahead, ou seja,sintacticamente correcto deve ser possível partir no caso abaixo ele não consegue decidir se ode program e derivar todos os elementos que o que recebeu foi o x ou o y porque no momentocompõem. Neste caso program é o símbolo de escolher a produção ele só sabe que o seinicial da gramática, e indicamos isso ao byacc segue é o token C. Como existem dois casoscolocando-o como a primeira produção do com o token C, ele não sabe o que fazer. Istoficheiro. não é um problema com a gramática, é umaJá vimos nos exemplos anteriores que as limitação do byacc.produções podem ser recursivas, o corpo dumaprodução pode conter o mesmo não terminal s : x C Dque é a cabeça. A recursividade é necessária e | y C Falgo que o byacc processa muito eficientemente, ;mas usada sem cuidado é uma das coisas que x : A B;introduz conflictos na gramática. Um conflicto y : A B;surge quando o parser não sabe que regra usarpara uma determinada sequência de tokens. Um O mesmo não ocorre no caso seguinte. Nestaexemplo segue-se: situação ele consegue saber que produção usar vendo se o lookahead é D ou F. 14
  14. 14. A PROGRAMAR BYAC C s : x D %nonassoc IFX | y F %token ELSE ; x : A B; ... y : A B; %%A existência de conflictos na gramática nãoimpede o parser de ser gerado, já que o byacc ...tem comportamentos default quando não sabeque produção usar, mas claro que o stmt : IF expression stmt %prec IFXcomportamento default pode não ser o que o | IF expression stmt ELSE stmtprogramador tinha em mente quando escreveu a ;gramática portanto convém eliminar os conflictosantes de gerar o parser. ... %%Os conflictos são introduzidos na escrita dagramática e podem sempre ser eliminadosreescrevendo-a, mas por vezes é preferível Introduzimos o token IFX - o token ELSE já temeliminá-los usando precedências. Tomemos o de estar definido, tal como o IF se o estamos aseguinte exemplo clássico, o “dangling else”: usar na gramática - que não é retornado pelo scanner. O IFX só existe dentro do parser e stmt : IF expression stmt serve apenas para indicar o nível de | IF expression stmt ELSE stmt precedência de uma produção. Indicamos ao ; byacc o nível de precedência dos tokens pela ordem em que os declaramos, tendo os últimosPara o seguinte input: maior precedência que os primeiros. A precedência de um token determina a if(a) precedência da produção em que ele se if(b) c = a + b; else c = a; encontra, numa situação em que duas produções são viáveis como no exemplo anteriorO problema que nos surge é que o parser não a produção com maior precedência é usada. Sesabe se o que ele tem é um IF expression stmt quisermos modificar a precedência de umacom expression igual a (a) e o stmt igual a if(b) c produção sem afectar a precedência de nenhum= a + b; else c = a; ou se em vez disso tem um dos seus tokens, podemos, como mencionadoIF expression stmt ELSE stmt com expression previamente, criar um token “falso” como o IFX etambém igual a (a), o primeiro stmt igual a if(b) c escrever %prec IFX no fim da produção para o= a + b; e o segundo stmt igual a c = a;. O que conseguir. Usando o token IFX no primeiro IFqueremos que o parser faça? Associe o else ao estamos a dizer que aquele tipo de if tem menosprimeiro if ou ao segundo? O comportamento precedência que o segundo IF,já que o token IFXque esperamos é que associe ao segundo, é declarado antes do token ELSE, portantoportanto para o conseguir vamos usar quando existem as duas hipóteses o parserprecedências. escolhe sempre a segunda, o que é o comportamento que desejávamos. 15
  15. 15. A PROGRAMARBYAC C expr : expr * expr | expr ^ expr | NUMBER | ( expr ) ; ;Neste caso para o input NUMBER * NUMBER * Dizemos que os operadores binários + e - sãoNUMBER por exemplo, o parser não sabe se há- associativos à esquerda e têm a mesmade fazer (NUMBER * NUMBER) * NUMBER ou precedência. Os operadores * e / funcionam deNUMBER * (NUMBER * NUMBER). Para forma idêntica mas têm maior precedência. Oresolver este problema precisamos de indicar a operador de potência ^ é associativo à direita eassociatividade do operador binário * ao byacc. tem a maior precedência de todos os operadoresUm operador com associatividade à esquerda binários. O UMINUS indica que uma expressãopara o input NUMBER * NUMBER * NUMBER * negada tem a maior precedência e que não seNUMBER faz ((NUMBER * NUMBER) * pode negar uma negação. Os parênteses forçamNUMBER) * NUMBER, um operador com a avaliação de qualquer que seja a expressãoassociatividade à direita faz NUMBER * que estiver dentro deles, contornando as(NUMBER * (NUMBER * NUMBER)) para o precedências caso seja necessário. Para o input,mesmo input. A forma de indicar a -1 ^2 + 5 + 3 - 2 * 3 ^ 4 ^ 5 / -6 / 2 - 5 a nossaassociatividade de um token ao byacc é gramática vai fazer (((((-1 )^2) + 5) + 3) - (((2 * (3escrever %left ou %right em vez de %token ^ (4 ^ 5))) / (-6)) / 2)) - 5 como seria de esperar.quando o declaramos. Para declarar umoperador unário não associativo (ou seja um Podemos associar acções a cada produção,operador que não se pode encadear) para serem executadas quando o parser acabaescrevemos %nonassoc em vez de %token. de processar o corpo de uma produção e o substitui pela cabeça. As acções indicam-se daEntendendo associatividade e precedências mesma forma que no scanner, e é possível usarpodemos começar a compreender a gramática elementos da produção dentro delas desde queda nossa calculadora. eles tenham valores associados. Para indicar o valor da cabeça usamos $$, para os membros %token NUMBER do corpo usamos $1 , $2, … $n de acordo com a ordem em que eles aparecem. Um não terminal %left + - tem por default associado um int. Se quisermos %left * / associar um tipo diferente declaramos %right ^ %type<tipo-do-valor-associado> nome-do- %nonassoc UMINUS símbolo-não-terminal na primeira secção do ficheiro. Vejamos então o ficheiro inteiro: %% %% expr : NUMBER %{ | - expr %prec UMINUS #include <iostream> | expr + expr #include <cmath> | expr - expr %} | expr * expr | expr / expr 16
  16. 16. A PROGRAMAR BYAC C tipos associados, %union { associatividade e double d; precedência. Concluímos a }; primeira secção com a declaração que o símbolo não %token<d> NUMBER terminal expr tem um valor %token NL associado do tipo double. Isto %left + - é essencial porque as nossas %left * / operações não estão a %right ^ receber tokens NUMBER %nonassoc UMINUS como argumentos mas sim %type<d> expr não terminais expr. O símbolo inicial da nossa gramática é %% expr_list e está definido como expr_list : expr NL { std::cout << $1 << std::endl; } uma sequência de um ou mais | expr_list expr NL { std::cout << $2 << std::endl; } não terminais expr, separados ; por mudanças de linha. Associamos a cada produção expr : NUMBER { $$ = $1; } de expr_list a acção da | - expr %prec UMINUS { $$ = -$2; } impressão do valor de expr. | expr + expr { $$ = $1+$3; } As produções com cabeça | expr - expr { $$ = $1-$3; } expr tem associadas as | expr * expr { $$ = $1*$3; } acções que realizam os | expr / expr { $$ = $1/$3; } cálculos, guardando os | expr ^ expr { $$ = pow($1, $3); } valores na cabeça. Na terceira | ( expr ) { $$ = $2; } secção temos um main que ; chama o yyparse(). %% int main() Neste momento temos um { parser e um scanner para a yyparse(); nossa calculadora, no próximo } artigo veremos como ligá-los eO ficheiro começa com os #includes de C++ que como modificar o scanner e oprecisamos, seguidos da %union com o único parser em conjunto de forma a adicionar maistipo que a nossa calculadora necessita, um funcionalidades à calculadora.double. Lemos a declaração dos tokens, com os AUTOR Escrito por João Mares Estando actualmente no terceiro ano de LEIC no IST, interssa-se preferencialmente por arquitectura de computadores e computação gráfica. 17
  17. 17. VISUAL (NOT) BASICI n tro d u ç ã o a o E n ti ty Fra m e wo rkO ADO.NET Entity Framework permite criar tenham como nome “Jorge” e que tenham comoaplicações em que o acesso a dados é feito com morada a “Moita”.base em um modelo conceitual e não utilizandocomandos directos à base de dados. Isto Imaginemos que o programador ou o DBApermite que o programador se abstraia (database administrator) altera o campo “nome”totalmente da base de dados (criação de para “nomecompleto”, pois quer que se registe oligações de acesso, comandos, parâmetros, etc.) nome completo do utilizador e, desta forma, oe utilize apenas objectos durante o nome do campo fica mais coerente. Sedesenvolvimento. aplicação for compilada não é detectado qualquer problema e só no momento deA versão 4.0 do Entity Framework (actual), que execução irá ocorrer um erro. Situações comoestá disponível na .NET Framework 4.0, tem um estas são muito frequentes e podemconjunto de novas funcionalidades e melhorias, representam vários erros na aplicação.como é o caso de suporte a POCO - Plain OldCLR Objects (permite criar classes que não Este é apenas um exemplo de como se podeherdam, nem implementam nenhuma outra beneficiar, e muito, da utilização do Entityclasses ou interface), abordagem Model-First Framework, mas existem muito mais vantagens(permite criar primeiro o modelo conceptual e, como a utilização de LINQ to Entities,com base nele, criar a base de dados), suporte intellisense no momento em que se está apara o uso de funções em LINQ-to-Entities, escrever o código, código mais fácil de manter eComplex Types (criação de tipos de dados actualizar, etc, etc.complexos), Deferred Loading ou Lazy Loading(capacidade de carregar as propriedades de Neste artigo, que será uma breve introdução aoassociação das entidades no momento em são Entity Framework, irá apenas mostrar comochamadas, se forem chamadas), etc. Não é construir um modelo relacional de uma base deespecifica apenas para o SQL Server, pois dados SQL, uma abordagem database-first, eexistem providers que permitem usar outras como executar algumas operações CRUD.bases de dados, como Oracle, MySql,PostgreSQL, DB2, SQL Anywhere, Ingres, CRIAÇÃO DO MODELO RELACIONALProgress, Firebird, Synergy, etc. (database-first)Existem várias vantagens na utilização de um Para criação de um modelo relacional iremosORM (Object-relational mapping), que tornam a usar a seguinte base de dados SQL:sua adopção quase inevitável, mas vejamos oseguinte exemplo:“SELECT * FROM utilizadores WHERE nome =‘Jorge’ AND morada = ‘Moita’”Este exemplo irá listar todos os utilizadores que 18
  18. 18. VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rk Para o nome da ligação, e para este exemplo,Como é possível ver nesta imagem, existem utilize “vendasEntities“.apenas 3 tabelas, com as respectivas chavesprimárias/estrangeiras: produtos, clientes e uma A última opção deste Wizard é onde sãoterceira tabela onde se registam os movimentos. seleccionados os objectos a utilizar no modelo. Neste exemplo são escolhidas as três tabelas jáO primeiro passo é adicionar um novo item ao referidas.projecto (menu Project – Add New Item), eseleccionar no grupo de templates “Data” o item“ADO.NET Entity Data Model”. Isto irá iniciar umWizard que permitirá criar o modelo final.De seguida seleccionar “Generate fromdatabase” e carregar em “Next”. Após este processo está criado o ficheiro EDMX,A próxima opção permite fazer a ligação à base que não é mais do que um conjunto de classes ede dados, escolhendo uma já existente ou métodos que nos permitirá aceder à base decriando uma nova ligação. dados de uma forma simples, como iremos ver de seguida. OPERAÇÕES CRUD As operações CRUD (acrónimo de Create, Read, Update e Delete em Inglês) são quatro operações básicas e fundamentais para a manipulação de bases de dados. São por isso 19
  19. 19. VISUAL (NOT) BASICI n tro d u ç ã o a o E n ti ty Fra m e wo rkbastante importantes e requerem, sem autilização de um ORM como o Entity Framework, context.clientes.AddObject(cliente)algum trabalho que é normalmente complexo. context.SaveChanges()Com o Entity Framework este trabalho está Podemos verificar logo o númerobastante simplificado para o programador, (ID) do registo inseridonecessitando apenas de algumas linhas de Debug.WriteLine("Número de registo: " &código, com recurso a IntelliSense, para as cliente.id.ToString())executar. End UsingO funcionamento para todas as operações ésemelhante: é criada uma nova instância danossa entidade (neste exemplo “vendasEntities”) Apagar registosque herda de uma classe da EntityFrameworkchamada ObjectContext, que a classe primária e Para apagar um registo é necessário seleccionarresponsável de gerir a informação como o registo correcto, neste caso usando umaobjectos e a ligação dos objectos aos dados. Lambda Expression, e caso o resultado seja válido, executamos o método DeleteObject(),Inserir registos indicando o registo a apagar.Para inserir novos registos, neste caso um novo Finalmente gravamos as alterações na base decliente, criamos uma nova instância da dados.respectiva classe, definindo as suaspropriedades, que correspondem aosrespectivos campos. Depois adicionamos oobjecto através do método AddObject() e, Using context As New vendasEntitiesfinalmente, executamos o métodoSaveChanges() que irá efectuar as respectivas Procura o registo com o número dealterações, neste caso inserir um registo, na cliente (ID) igual a 1base de dados. Dim cliente = context.clientes.Where( Function(c) c.id = 1). FirstOrDefault() Using context As New vendasEntities If cliente IsNot Nothing Then context.clientes.DeleteObject(cliente) Cria um novo cliente context.SaveChanges() Dim cliente As New clientes With Else { MessageBox.Show( .nome = "Rui Paulo", "Número de cliente inválido") .morada = "Lisboa", End If .datanascimento = New DateTime(1980, 10, 31) End Using } 20
  20. 20. VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rkModificar Registos Using context As New vendasEntitiesPara modificar um registo, e à semelhança da Dim listaClientes =operação anterior, é necessário seleccionar o From c In context.clientesregisto. Neste exemplo utilizamos LINQ to Where c.morada.Contains("Lisboa") AndEntities para fazer essa selecção. Depois, c.datanascimento <modificamos o que for para modificar e New DateTime(1985, 1, 1)finalmente gravamos as alterações. Select c Using context As New vendasEntities For Each c As clientes In listaClientes Debug.WriteLine(c.nome) Dim cliente = Next (From c In context.clientes Where c.id = 1 End Using Select c).FirstOrDefault() Entre entidades existir normalmente If cliente IsNot Nothing Then associações, e essas associações (também With cliente representadas na última imagem), têm algo que .nome = "Rui Paulo" se designa por Navigation Properties. As .morada = "Setúbal" Navigation Properties permitem uma navegação .datanascimento = bidireccional entre entidades, de acordo com as New DateTime(1979, 10, 31) suas associações. Isto é algo bastante prático End With pois permite-nos criar queries entre várias context.SaveChanges() entidades usando LINQ to Entities. Else MessageBox.Show( O seguinte exemplo mostra esta abordagem, "Número de cliente inválido") definindo depois o resultado como DataSource End If num controlo DataGridView. End Using NOTA: Se utilizar uma base de dados anexa ao Using context As New vendasEntitiesListar Registos Dim listaClientes = From c In context.clientesA listagem de registo é também muito Join m In context.movimentossemelhante às operações anteriores. Neste On m.clienteid Equals c.idexemplo, usando LINQ to Entities, vamos Join p In context.produtosseleccionar todos os registo com base num On m.produtoid Equals p.idcritério, para uma variável do tipo IQueryable(Of Select m.datavenda,T), e depois efectuamos um ciclo para mostraros resultados obtidos. 21
  21. 21. VISUAL (NOT) BASICI n tro d u ç ã o a o E n ti ty Fra m e wo rk Select m.datavenda, especiais), etc c.nome, p.produto, Estas são apenas algumas, das muitas m.preco vantagens, que nos devem fazer de uma vez por todas, deixar de usar SqlCommands, Me.DataGridView1.DataSource = listaClientes SqlConnections, DataSets, etc. End Usingprojecto (AttachDb), a base de dados é copiadapara as pastas Debug/Release. Pode Alguns recursos interessantes:seleccionar no menu Project a opção Show AllFiles e verificar as alterações nessa localização. Data Developer Center http://msdn.microsoft.com/en-us/data/ef.aspxCONCLUSÃO Data Access Hands-on Labs http://msdn.microsoft.com/en-Como foi possível ver ao longo do artigo, que us/data/gg427655.aspxabordou de uma forma muito superficial algumasdas funcionalidades deste ORM, o Entity ADO.NET team blogFramework é uma excelente opção para se http://blogs.msdn.com/b/adonet/trabalhar com bases de dados. Julie Lermans BlogÉ simples de utilizar, permite-nos trabalhar http://thedatafarm.com/blog/apenas com objectos e com intellisense, resolveinúmeros problemas que são habituais quandotrabalhamos directamente com a base de dados(formatos de datas, números, caracteres AUTOR Escrito por Jorge Paulino Exerce funções de analista-programador numa multinacional sediada em Portugal. É formador e ministra cursos de formação em tecnologias Microsoft .NET e VBA. É Microsoft Most Valuable Professional (MVP), em Visual Basic, pela sua participação nas comunidades técnicas . É administrador da Comunidade Portugal-a-Programar e membro de várias comunidades (PontoNetPT, NetPonto, MSDN, Experts- Exchange, CodeProject, etc). É autor do blog http://vbtuga.blogspot.com - twitter @vbtuga 22
  22. 22. A PROGRAMARPro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )Começo com este artigo uma série de artigos sobre PF por exemplo). Como já há váriosrelacionados com a Programação Funcional em artigos sobre PF em diversas linguagens, comoPerl. Python, Scheme, Haskell (recomendo que os leiam), deixo aqui a sugestão a alguém, paraNesta série de artigos pretendo demonstrar redigir um artigo teórico e agnóstico (em relaçãoalgumas das capacidades do Perl para utilização a linguagens de programação) sobrecom o paradigma de Programação Funcional. Programação Funcional.Não pretendo ensinar nem as bases da Umas das principaisProgramação Funcional, nem do Perl. Vou abrir características do Perlexcepções quando se tratarem de aspectos maisavançados e/ou muito relacionados com a (...) é não obrigar oprópria Programação Funcional. A compreensão programador a utilizar (...)elementar do Perl e da Programação Funcional mas sim permitir aoé um requisito para a compreensão destesartigos contudo tudo será explicado de forma a programador utilizar o quepermitir que um principiante possa compreender quiser quando quisertudo e quem tiver dúvidas poderá contactar-mepara as esclarecer. Algumas das funcionalidades elementares das linguagens funcionais são as funções anónimasUmas das principais características do Perl, em e as closures. O Perl tem ambas as features.seguimento do mantra da sua comunidade(«Theres more than one way to do it»), é não Uma das alterações que o Perl 5.1 2 trouxe foiobrigar o programador a utilizar, ou escolher um uma função chamada say. O say é basicamenteparadigma de programação, mas sim permitir ao um print que adiciona um newline à string queprogramador utilizar o que quiser quando quiser, queremos imprimir (poupa-nos pelo menos 4ficando ao cuidado dele ter os cuidados caracteres).necessários para que o código seja útil e sigaboas práticas de programação. Há quem Qualquer uma das seguintes linhas de códigoconcorde com esta filosofia, há quem não vai imprimir isolado numa linha a string: «Helloconcorde, mas a filosofia do Perl e da sua world!»:comunidade não é o âmbito deste artigo. print "Hello world!n";Um dos muitos paradigmas de programação que print "Hello world!"."n";são possíveis utilizar em Perl é a Programação print "Hello world!", "n";Funcional (PF). Contudo não cabe a este artigo say "Hello world!";explicar a PF. Por isso sugiro que antes deprosseguirem na leitura deste artigo leiam pelomenos uma curta explicação do que é PF (osprimeiros parágrafos do artigo da Wikipedia 23
  23. 23. A PROGRAMARPro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )Para demonstrar a utilização de funções utilização nas "dispach tables":anónimas decidi criar uma implementação dafunção say que permite definir antes da sua my %lingua = ( #dispach tableutilização como queremos que a string seja "pt" => sub { return "Olá mundo!" },formatada: "es" => sub { return "Hola mundo!" }, "en" => sub { return "Hello world!" }, sub say { #definição da função say "fr" => sub { return "Bonjour monde!" }, my ($string, $format) = @_; ); my $str = $format->($string); print $str; sub dispach { } my $l = shift; my $format = sub { #função anónima de if(defined $lingua{$l} && exists formatação da string $lingua{$l}) { my $str = shift; my $str = $lingua{$l}->(); return $str."n"; print $str."n"; }; } say("Hello world!", $format); else { print "Erro: lingua desconhecida!n"; }Explicação do código do exemplo anterior: } dispach("fr");Primeiro começamos por definir a função say,como definiríamos qualquer outra função emPerl. Depois definimos a função anónima deformatação, e atribuímos essa função a umavariável (que guarda uma referência para Explicação do código do exemplo anterior:código) para que possa ser passada de formavisualmente mais limpa à função say Começou por ser definido uma hash table que,(poderíamos também ter definido a função como chaves contém, as opções válidas deanónima, na invocação de say mas faria com línguas que queremos utilizar na impressão deque o código fosse muito menos legível). uma saudação e como valores, tem funções anónimas que imprimem uma saudação na língua representada pela sua chave na hashQual a utilidade das funções anónimas? table.As utilidades são diversas. E vão desde a Isto poderia ter sido feito definindoutilização das funções anónimas para poder individualmente funções "regulares", criandomodificar o comportamento de uma função que variáveis que eram referências para cada umatenha sido criada para poder permitir essa dessas funções e utilizando essas variáveisalteração. Há quem utilize isto para poder por como valores a utilizar na hash table.exemplo poder voltar a correr código que tinhasido serializado. E passam pela utilização em Mas isso traria imediatamente dois problemas:"dispach tables". Uma outra utilidade é a aumentaria a quantidade de código necessário e este artigo tem um limite de caracteres; não 24
  24. 24. A PROGRAMAR Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )utilizaria funções anónimas, que é o objectivo solução escale para mais opções de línguas,deste exemplo ;). sem qualquer alteração e atinge melhor vários dos objectivos da utilização de funções naPara além de isso, o que é pretendido neste programação: conter/isolar os problemas deexemplo, é algo tremendamente simples que forma a simplificar a sua resolução, facilitar apode perfeitamente ser feito utilizando funções compreensão do código.anónimas, sem se aumentar a dificuldaderelevante da sua compreensão como um todo eem parte. No próximo, artigo vou falar da segunda das principais capacidades do Perl para a Programação Funcional de que falei antes, asA opção por esta solução, em vez de a utilização closures.de um encadeamento maior de if-elsif, ou de umswitch-case (também maior) permite que a (...) permite que a solução escale para mais opções de línguas, sem qualquer alteração e atinge melhor vários dos objectivos da utilização de funções na programação (...) AUTOR Escrito por Diogo Constantino é Consultor na área as tecnologias licenciadas como Software Livre, com aproximadamente vários anos de experiência profissional, especializado em desenvolvimento com Perl. Larga experiência na área de sistemas, engenharia e de operações de redes de telecoms, tendo desenvolvido, mantido e utilizado ferramentas para diversas telecoms nestas áreas. Conhecimentos em tecnologias como Perl, Python, PHP, MySQL, GNU/Linux, C, HTML, CSS, Javascript, GNU/Linux. Tendo tido ainda contacto profissional com tecnologias como Switchs, equipamentos de routing, firewalling e switching de diversos fabricantes, diversos sistemas *nix e diversas outras ferramentas e tecnologias comuns em sistemas *nix e/ou utilizadas em empresas de telecomunicações, redes e web. Relativamente conhecido advogado da causa do Software Livre em diversas comunidades. Sócio da Associação Nacional para o Software Livre e da Associação Portuguesa de Programadores de Perl. 25
  25. 25. COMUNIDADE NETPONTOB a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e mWi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF)Neste artigo pretendo mostrar o que é o System.ComponentModel. Esta classe permite-BackgroundWorker e vou exemplificar como se nos ajudar a gerir uma tarefa numa threaddeve proceder à sua implementação usando a separada da thread principal sem termos de nostecnologia WPF na versão .Net Framework 4. preocupar com a inicialização e gestão da thread onde vamos executar a tarefa.Suponhamos: As propriedades a ter em conta são:“Tenho um algoritmo complexo de Optimização Combinatória que irá ter como parâmetro de CancellationPending entrada um objecto do tipo World. Classe que Permite obter se a tarefa foi cancelada. define toda a estrutura de dados da minha aplicação e no final retorna o objecto World com WorkerReportsProgress as alterações realizadas pelo algoritmo.” Permite obter e definir se o BackgroundWorker vai reportar o seu progresso da tarefa.Esta geração vai implicar que tenhamos pelomenos três passos: WorkerSupportsCancellation1 . A partir do objecto World vamos criar a Permitir obter e definir se o BackgroundWorkerestrutura de dados do algoritmo; vai permitir cancelar a tarefa.2. Gera-se o algoritmo a partir dos dadosrecebidos; Os métodos a ter em conta são:3. Depois de gerar o algoritmo é precisoconverter o resultado de forma a reflectir no RunWorkerAsyncWorld o resultado do algoritmo; Permite iniciar a tarefa. Existem duas assinaturas deste método. UmaEnquanto estes três passos estão a decorrer, eu delas não tem argumento, a outra que o temquero ser informada sobre o progresso da utiliza-o na execução da tarefa.geração do algoritmo e pretendo ter acapacidade de a cancelar. CancelAsync Permite cancelar a tarefa e consequentemente oEste cenário é um dos muitos cenários onde o BackgroundWorker irá terminar.BackgroundWorker pode ser implementado. Para que seja possível cancelar a tarefa éOutros exemplos reais são a leitura de ficheiros necessário que a propriedadeextensos, aceder a base de dados para efectuar WorkerSupportsCancellation tenha o valor deo carregamento de dados, fazer o load de verdade true.imagens e gerar relatórios. ReportProgressAntes de passarmos à implementação vou dar Permite reportar o progresso da tarefa em dadouma breve apresentação teórica: momento. Para que o progresso seja reportado éUm BackgroundWorker é uma classe contida no necessário que o WorkerReportsProgress tenha 26

×