jesu 0 Posted October 14 Hello. I'm trying to create a function that can return a float or nil: function myfunc(const pa_value:string): double; begin if pa_value = whatever then result := -1 else result := nil; end; to replace many lines like this (simplified code): if check then parambyname('myparam').asfloat := -1 else parambyname('myparam').clear; What is the right way to do that? Thanks. Share this post Link to post
Virgo 18 Posted October 14 Using variant? function myfunc(const pa_value:string): variant; begin if pa_value = whatever then result := -1 else result := null; end; and then parambyname('myparam').AsVariant := myfunc(); Share this post Link to post
FPiette 385 Posted October 14 It depends on what your function does, but just like a function returning an integer returns a special value (often -1 or 0) in case of error, your function could return a special value as a double number. Carefully select the value so that it doesn't collide with expected values in your application. I'm think about a value like 2.12345e-308. Just define a constant to give that value a nice name easy to use and remember. Share this post Link to post
Anders Melander 1812 Posted October 14 30 minutes ago, FPiette said: Carefully select the value so that it doesn't collide with expected values in your application. I'm think about a value like 2.12345e-308. Just define a constant to give that value a nice name easy to use and remember. NaN 1 Share this post Link to post
FPiette 385 Posted October 14 1 hour ago, Anders Melander said: 2 hours ago, FPiette said: Carefully select the value so that it doesn't collide with expected values in your application. I'm think about a value like 2.12345e-308. Just define a constant to give that value a nice name easy to use and remember. NaN Anders, I'm not sure that NaN is a good choice because this special value is generated in other cases. Something like 2.12345e-308is a better choice and collision risk is much lower. Share this post Link to post
Anders Melander 1812 Posted October 14 I'm pretty sure that anyone asking for help with something as basic as this isn't handling, or even aware of, NaN. Regardless, I personally wouldn't solve the problem with a magic value. 1 Share this post Link to post
Der schöne Günther 316 Posted October 14 (edited) Jesu mentioned using Data.DB.TParams.ParamByName which returns a Data.DB.TParam object. TParam has a property Value which is a Variant. As much as I loathe these things, the approach by @Virgo seems to be the most fitting. Edited October 14 by Der schöne Günther 1 Share this post Link to post
Anders Melander 1812 Posted October 14 It's impossible to suggest a good solution without knowing more about the context. If it's just a case of either setting or clearing a TParam value then just pass the TParam to the function and let the function operate directly on that. Share this post Link to post
Brandon Staggs 283 Posted October 14 You're better off doing something like function myfunc(const InVal: String; out OutVal: Double): Boolean; Return True if the value was set and false if not. There are other ways to handle this but the worst way is a magic value in Double. There's no reason to do that when it is so easy to indicate explicitly whether or not the value is valid. 7 Share this post Link to post
dummzeuch 1515 Posted October 15 I usually prefix functions like this with "Try", so instead of function GetTheValue(parameters ...): SomeType; it's function TryGetTheValue(parameters ...; out Value: SomeType): Boolean; 4 Share this post Link to post
Roger Cigol 107 Posted October 15 2 hours ago, dummzeuch said: TryGetTheValue( Very good suggestion by @dummzeuch Very few people give enough thought to naming of functions and variables. Developing a consistent approach can significantly help with long term program readability / long term support for large projects. Anything that hints at doing that gets my full support ! https://cigolblog.wordpress.com/2023/01/ https://cigolblog.wordpress.com/2019/10/ https://cigolblog.wordpress.com/2017/06/ 2 Share this post Link to post
jesu 0 Posted October 18 (edited) Thanks for the suggestions. Returning a dummy value would mean rewriting the stored procedures so that's a no-no. I'm trying to avoid Variants because in the past I've had problems with variants <-> float. I've tried this instead procedure ProcValorDeCombo(var pn_param: TFDParam; pt_Combo: TComboBox); var vn_marca: double; begin case pt_Combo.ItemIndex of -1: begin // code ... pn_param.AsFloat := vn_marca; end; // code... else pn_param.Clear; end; end; but when I try to call it ProcValorDeCombo(ParamByName('myparam'), mycombo); I get E2197 Constant object cannot be passed as var parameter Edited October 18 by jesu Share this post Link to post
Der schöne Günther 316 Posted October 18 Why did you mark the parameter as var in the first place? Share this post Link to post
Anders Melander 1812 Posted October 18 26 minutes ago, jesu said: Because I'm modifying it inside the procedure ... ok, I'm not modifying tparam, but tparam.value The TFDParam parameter is an object reference (i.e. a pointer). You are not modifying the object reference; You are modifying a property on the object. So drop the var. I would also change the TComboBox parameter to an integer and pass TComboBox.ItemIndex instead; There's no reason to create a dependency on TCombobox when all you need is the ItemIndex. Share this post Link to post
jesu 0 Posted October 18 Right, I've removed var and it works, but the combobox style is csDropDown so I check both itemindex and text. And there are lots of them, so if I have a problem I use the name to find which one is wrong. Share this post Link to post
pmcgee 22 Posted December 6 (edited) @jesu I see this was a while back, but I'd encourage you to look up the idea of an Optional type. (One of) the points of an optional type, is that it doesn't reduce the value space of your inhabited type. Using 'NaN' or '-1' or whatever as a magic value might interfere with the validity of your use of the Double value. With an optional type , the inhabited type is uncontaminated by any other interpretation or usage. You can look at what it looks like in eg Spring4D, but here's the basic idea : type Maybe_Double = record // or Optional_Double ok : boolean; d : double; end; function Safe_Sqrt( i:integer ) : Maybe_Double; begin if i<0 then result.ok := false else begin result.ok := true; result.d := sqrt(i); end; end; begin for var i:= -2 to 2 do begin var ss := Safe_Sqrt(i); if ss.ok then writeln(i, ' ', d) else writeln(i, ' ','Undefined'); end; end. PS : Another feature of an optional type is that all uses of the inhabited type transfer into the "optional world". // If you have a function F( d:double ) : string, // then you can automatically have an 'identical' function OptF( od:maybe_double ) : maybe_string; begin if od.ok then exit( F(od) ) else exit( <the nil case> ) end; Edited December 6 by pmcgee Share this post Link to post
Tommi Prami 131 Posted December 9 (edited) Or just "setter" method with original code. Something like... function SetFloatParameter(const ADataSet: TDataSet; const AParamName: string; const AValueOK: Boolean; const AFloatValue: Double); begin Result := False; if AValueOK then begin ADataSet.ParamByName(AParamName).AsFloat := AFloatValue; Result := True; end else ADataSet.ParamByName(AParamName).Clear; end; Edited December 9 by Tommi Prami Share this post Link to post