Can anyone comment on the extraction of the linear part in varf() ?
There is an issue of sign, it seems that it is treated differently depending if it is an integral source or an on() boundary condition. The simple code

int n=3;
mesh Th=square(n,n);
//plot(Th);
real a=1.,b=1.;
fespace Vh(Th,P1);
Vh u,v;
real[int] tab(Vh.ndof),sol(Vh.ndof),solprob(Vh.ndof),diff(Vh.ndof);
solve prob(u,v)
=int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
-int2d(Th)(a*v)
+on(1,2,3,4,u=b)
;
solprob=u[];
//cout << "solprob = " << solprob << endl;
varf test(u,v)
=int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
-int2d(Th)(a*v)
+on(1,2,3,4,u=b)
;
matrix A=test(Vh,Vh);
tab=test(0,Vh);
tab=-tab;// it seems necessary for the source "a", but not for boundary "b"
sol=A^-1*tab;
//cout << "sol = " << sol << endl;
diff=solprob-sol;
cout << "error = " << sqrt(diff'*diff) << endl;

considers either solve() or varf() with the same problem, but they do not give the same solution.
??

solve supposes the linear and bilinear form represent the LHS and RHS of an equation system. varf defines a linear or bilinear form that is not necessarily part of an equation.

Since you impose inhomogeneous BC, the sign flip in the latter is changing the BC, not just the forcing.

varf test(u,v)
=int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
+int2d(Th)(a*v) // note: sign flip is here now
+on(1,2,3,4,u=b)
;
matrix A=test(Vh,Vh);
tab=test(0,Vh);
// line removed here
sol=A^-1*tab;

Another equivalent option would be:

varf test(u,v)
=int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
-int2d(Th)(a*v)
+on(1,2,3,4,u=-b) // note: sign flip is here now
;
matrix A=test(Vh,Vh);
tab=test(0,Vh);
tab=-tab;// it seems necessary for the source "a", but not for boundary "b"
sol=A^-1*tab;

Thank you. It is quite puzzling that solve and varf do not use the same conventions. Additionally in varf the convention for int2d or int1d is opposite to that of on(). Then I have to remind of it when changing from one formulation to the other. Setting u=-b instead of u=b is very much counterintuitive (your second option). The first option is also counterintuitive since it looks like we are not solving the right equation (-\Delta u+a=0 instead of -\Delta u-a=0).

Additionally in varf the convention for int2d or int1d is opposite to that of on()

You are thinking that there is a convention, but there is none. int2d or int1d are used to discretise linear or bilinear form (which may be related or not, as Chris highlighted). on() is used to impose Dirichlet boundary conditions. That’s two different things, hence there is no convention between one and the other.

Why would you want to avoid the use of on()? That allows more flexibility in terms of how Dirichlet BC’s are enforced via penalization tgv>0, or elimination (asymmetric tgv=-1 or symmetric tgv=-2). It also allows you to ignore BC with tgv=0.

On the generic problems of the type I mentioned on my first post, it is possible to use the third option, which does the job in any type of formulation (solve, problem, varf).
This does not mean I “want” to avoid on().