Is there anything in ADVPL equivalent to the lambda function of Java?

3

I'm servicing an ADVPL project. In it, I have some source files. Among these sources, I have an information miner in the GEO1 file and a communicator of the information mined in the GEO3 file.

In the initial operation, the loads were low and the extraction was done first, only then to communicate to the external system about these changes. It turns out that this initial load is larger than initially expected, so I'm refactoring the system to perform the upload during the extraction.

If it was something in Java, which I have more custom, would make a more functional approach by passing a Consumer to my Extractor. It would look like the following was the original code:

class Minerador {
  public List<InformacaoMinerada> mineraInformacoes() {
    List<InformacaoMinerada> info = new ArrayList<>();

    while (temInformacaoMineravel()) {
      info.add(minerarProximaInformacao());
    }

    return info;
  }
  private InformacaoMinerada minerarProximaInformacao() {
    // código de mineração que posso desconhecer, lei de Deméter
    ...
    return stuff;
  }
}

class Comunicador {
  public void enviaDados(List<InformacaoMinerada> informacoes) {
    // detalhes internos do envio
  }
}

class Principal {
  public static void main() {
    Minerador miner = getMiner();
    Comunicador mercurio = getComunicador();

    mercurio.enviaDados(miner.mineraInformacoes());
  }

  public static Minerador getMiner() {
    // inicia o minerador corretamente
    return miner;
  }

  public static Comunicador getComunicador() {
    // inicia o minerador corretamente
    return comunicador;
  }
}

In the transformation, I would have the communicator be warned that there is new information and, according to a threshold, would send the received information:

class Minerador {
  public void mineraInformacoes(Consumer<InformacaoMinerada> consumidorInformacao) {
    List<InformacaoMinerada> info = new ArrayList<>();

    while (temInformacaoMineravel()) {
      consumidorInformacao.accept(minerarProximaInformacao());
    }
  }

  private InformacaoMinerada minerarProximaInformacao() {
    // código de mineração que posso desconhecer, lei de Deméter
    ...
    return stuff;
  }
}

class Comunicador {
  private List<InformacaoMinerada> informacoesBufferizadas;
  private int threshold;

  public void enviaDadosBufferizados() {
    if (informacoesBufferizadas.size() > 0) {
      enviaDados(informacoesBufferizadas);
      informacoesBufferizadas.clear();
    }
  }

  public void adicionaInformacao(InformacaoMinerada info) {
    informacoesBufferizadas.add(info);
    if (informacoesBufferizadas.size() >= threshold) {
      enviaDadosBufferizados();
    }
  }

  private void enviaDados(List<InformacaoMinerada> informacoes) {
    // detalhes internos do envio, mesmo código da enviaDados antiga
  }
}

class Principal {
  public static void main() {
    Minerador miner = getMiner();
    Comunicador mercurio = getComunicador();

    miner.mineraInformacoes(mercurio::adicionaInformacao);

    // para eventual envio de dados residuais
    mercurio.enviaDadosBufferizados();
  }

  public static Minerador getMiner() {
    // inicia o minerador corretamente
    return miner;
  }

  public static Comunicador getComunicador() {
    // inicia o minerador corretamente
    return comunicador;
  }
}

Is there anything equivalent to this lambda function in ADVPL?

    
asked by anonymous 16.11.2018 / 15:41

2 answers

2

There is something called Code Block, which is also a cloister also (with same problems that most languages have when they run in scenarios such as a loop for example). The idea is just that, but the inner workings are terrible.

This has already existed since Clipper and was well implemented there. In Harbor it went a little further and created a reference for the simpler cases that do not need closure, giving more efficiency (in the background it was a pointer, so they even call it Pointer , although technically it is a reference, as they call Hash a type that has two distinct implementations of the same type, it's a dread, and neither is a hash and you've seen that they are not good at giving names to things ).

Clipper always had something called a macro, because dBase had it, and in dBase it was mandatory because it did not have the most correct mechanisms. Clipper created them, but kept the macro for compatibility. It is basically a compiler, it can generate execution from a text. Something like a eval() . It is used with an "operator" & . Imagine that it is very slow and susceptible to errors, not to mention insecurity. So the code block was created. But ADVPL created only the macro, and to maintain compatibility with the Code Block syntax they turned it into macro internally, meaning performance is suffer.

It works like this:

aArray := { 0, 1, 2, 3 }
nValor := 5
Scan(aArray, {|i| conout(i + nValor) })

user function Scan(aArray, bAction) {
    for i := 0 to len(aArray)
        eval(bAction)
    next
return nil

I placed GitHub for future reference .

Print from 5 to 8.

In this case I used cloister in nValor , but it is not necessary if you do not need it. Use sparingly, just to give a complete example.

    
16.11.2018 / 16:06
1

There is a code block ( code block ).

You can see a use of the code block in the following example:

// arquivo Test1.prw

static function apendar(aArray, cStr)
  // se o threshold for 2:
  if len(aArray) >= 2
    msgInfo('fazendo a chamado do threshold e limpando o vetor')
    aArray := {}
  endif

  aAdd(aArray, cStr)
return

user function principal()
  local aVetor := {}
  local cVetorLegivel := ''
  local i

  u_fext('1', {|cStr| apendar(aVetor, cStr)})
  u_fext('2', {|cStr| apendar(aVetor, cStr)})
  u_fext('3', {|cStr| apendar(aVetor, cStr)})
  u_fext('4', {|cStr| apendar(aVetor, cStr)})

 for i := 1 to len(aVetor)
   cVetorLegivel  += aVetor[i] + ','
 next i
 MsgInfo(cVetorLegivel)
return
// arquivo Test2.prw

user function fext(cStr, bBloco)
  eval(bBloco, cStr)
  MsgInfo(cStr)
return

Note that the fext function is totally unaware of the implementation of bBloco , but is able to call it correctly through eval .

I made tests by passing the first argument of apendar to both the reference of the aVetor variable and using it directly and the results were the same:

// bloco de código usando 'aVetor' diretamente
{|cStr| apendar(aVetor, cStr)}

// bloco de código usando a referência a 'aVetor'
{|cStr| apendar(@aVetor, cStr)}
    
16.11.2018 / 15:56