How to model C char* that can be 0?

53 views
Skip to first unread message

H Zhang

unread,
Jan 23, 2014, 5:34:48 PM1/23/14
to ats-lan...@googlegroups.com
Some C library functions use zero valued pointer for special meaning. What is the best way to model this? I would like to use string to model char*, but then I can't assign the value zero to a variable of type string.

gmhwxi

unread,
Jan 23, 2014, 5:46:13 PM1/23/14
to ats-lan...@googlegroups.com
Take a look at 'stropt' (functional) or 'strptr' (linear).

gmhwxi

unread,
Jan 23, 2014, 5:48:46 PM1/23/14
to ats-lan...@googlegroups.com
When using these types, please get the 'cast' function ready :)
Proving stuff at this level may not be what you want to do right now.

Brandon Barker

unread,
Jan 23, 2014, 5:54:17 PM1/23/14
to ats-lan...@googlegroups.com
Relatedly, I was actually about to ask a similar question. How to do this in general (not just for char*)?

currently I was thinking of implementing a datavtype that is very similar to an option_vt but is either sometype or NULL (instead of sometype or void), where NULL is:

macdef NULL = $extype(ptr, "0")



For context, I have a C function that looks like this:

  GRBnewmodel(GRBenv *env, GRBmodel **modelP, const char *Pname, int numvars,
             
double *obj, double *lb, double *ub, char *vtype,
             
char **varnames);



Where an example call looks like this:

  error = GRBaddvars(model, 3, 0, NULL, NULL, NULL, obj, NULL, NULL, vtype,
                     NULL
);

Brandon Barker

unread,
Jan 23, 2014, 5:56:20 PM1/23/14
to ats-lan...@googlegroups.com
Interestingly, as a side note, it seems a bit odd that 0 is passed as the third argument: already dependent types could be useful in this scenario, since in their example, the number of variables (which I assume should be numvars) should be 3.

Brandon Barker
brandon...@gmail.com


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/678eb1df-cd7e-4e65-a422-80fcfe21c743%40googlegroups.com.

Brandon Barker

unread,
Jan 23, 2014, 5:57:10 PM1/23/14
to ats-lan...@googlegroups.com
Also, I pasted the wrong function call.. should be:
 error = GRBnewmodel(env, &model, "mip1", 0, NULL, NULL, NULL, NULL, NULL);

Brandon Barker
brandon...@gmail.com

H Zhang

unread,
Jan 23, 2014, 6:31:27 PM1/23/14
to ats-lan...@googlegroups.com
I used $UN.cast{string}(0) and that made the type checker happy. Checking the gcc -E output shows that the translated C code is as expected. It does read a little funny since it is not obvious at first sight that string is actually a ptr, so one may wonder how 0 is converted to a string.

gmhwxi

unread,
Jan 23, 2014, 8:33:16 PM1/23/14
to ats-lan...@googlegroups.com
string is a boxed type (that is, void*).

So $UN.cast{string}(0) essentially gives you the null pointer.

However,

length($UN.cast{string}(0)) segfaults.

Using stropt is a type-safe solution.

gmhwxi

unread,
Jan 23, 2014, 8:44:05 PM1/23/14
to ats-lan...@googlegroups.com
This is where ATS can shine.

As we can see, there are so many ambiguities here. For instance.

obj: &double >> _

or

obj: &double? >> _

When calling the function, should obj be initialized or not?

Brandon Barker

unread,
Jan 23, 2014, 9:20:50 PM1/23/14
to ats-lan...@googlegroups.com
Presumably (I only have the header and the example), it is going to be either an initialized pointer to doubles ( obj: &double >> _ ), or a NULL pointer. 

I imagine passing a NULL pointer could have strange behavior, but on testing it (passing an unitialized double* in C), it compiled and ran fine (but I guess we can exclude the possibility as it is a bit odd here).

So I wonder if it is advisable to attempt to model a datavtype that is either a  "&double >> _" or a  NULL, or if there's a more straightforward approach.

gmhwxi

unread,
Jan 23, 2014, 9:34:44 PM1/23/14
to ats-lan...@googlegroups.com
It is doable (I did it), but it makes things too complicated for the user.

You can use something like:

obj: cPtr0(double)

In general, this is good enough.

H Zhang

unread,
Jan 23, 2014, 11:27:57 PM1/23/14
to ats-lan...@googlegroups.com
However if I use stropt I seem to get trouble when assigning a string literal to it:

/home/haitao/pugi-store/pl_dlcall.dats: 894(line=31, offs=24) -- 907(line=31, offs=37): error(3): [/home/hwxi/research/Postiats/git/src/pats_trans3_util.dats]: d3exp_trdn: the dynamic expression cannot be assigned the type [S2Eexi(n(231); ; S2Eapp(S2Ecst(stropt_int_type); S2Evar(n(231))))].
/home/haitao/pugi-store/pl_dlcall.dats: 894(line=31, offs=24) -- 907(line=31, offs=37): error(3): mismatch of static terms (tyleq):
The actual term is: S2Eapp(S2Ecst(string_int_type); S2Eint(11))
The needed term is: S2Eapp(S2Ecst(stropt_int_type); S2EVar(3509))
/home/haitao/pugi-store/pl_dlcall.dats: 894(line=31, offs=24) -- 907(line=31, offs=37): error(3): mismatch of static terms (tyleq):
The actual term is: S2Eapp(S2Ecst(string_int_type); S2Eint(11))
The needed term is: S2Eexi(n(231); ; S2Eapp(S2Ecst(stropt_int_type); S2Evar(n(231))))

And line 31 is:
  val library = dlopen("testdll.dll", RTLD_GLOBAL)

H Zhang

unread,
Jan 23, 2014, 11:31:16 PM1/23/14
to ats-lan...@googlegroups.com
Explict cast to stropt fixes the compile, but in terms of semantics if something can be assigned to string then it should also be assigned to stropt?

gmhwxi

unread,
Jan 23, 2014, 11:34:42 PM1/23/14
to ats-lan...@googlegroups.com
val library = dlopen(stropt_some"testdll.dll", RTLD_GLOBAL)

gmhwxi

unread,
Jan 23, 2014, 11:35:36 PM1/23/14
to ats-lan...@googlegroups.com
Semantically, stropt = string + NULL

H Zhang

unread,
Jan 24, 2014, 12:11:30 AM1/24/14
to ats-lan...@googlegroups.com
That is great, but how is stropt defined? In basics_sta.sats:

abstype
stropt_int_type (n:int) = ptr
stadef stropt = stropt_int_type

How does it know about the constructor stropt_some?

gmhwxi

unread,
Jan 24, 2014, 12:18:27 AM1/24/14
to ats-lan...@googlegroups.com
stropt_some is not a constructor; it is a no-op cast function.
In mathematics, this is called embedding (since stropt = string + NULL).

Brandon Barker

unread,
Jan 24, 2014, 12:20:20 AM1/24/14
to gmhwxi, ats-lan...@googlegroups.com
I was about to suggest it might be in string.sats:

symintr stropt_some
castfn stropt0_some (x: SHR(string)): Stropt1
overload stropt_some with stropt0_some of 0
castfn stropt1_some {n:int} (x: SHR(string n)): stropt (n)
overload stropt_some with stropt1_some of 10

I find I have to dig around in a few files sometimes to find what I want.

For instance, just a few minutes ago, I found ptr2cptr in unsafe.sats, and cptr2ptr in pointer.sats (or vice versa).

Brandon Barker
brandon...@gmail.com


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.

gmhwxi

unread,
Jan 24, 2014, 12:23:09 AM1/24/14
to ats-lan...@googlegroups.com
ptr2cptr is unsafe but cptr2ptr is safe :)


On Thursday, January 23, 2014 5:34:48 PM UTC-5, H Zhang wrote:

H Zhang

unread,
Jan 24, 2014, 12:36:02 AM1/24/14
to ats-lan...@googlegroups.com, gmhwxi
Thanks. I saw that but I wasn't sure how it could be loaded as I don't explicitly staload string.sats. Then I remembered from digging around the pats src:

....
val () = pervasive_load (PATSHOME, "prelude/SATS/float.sats")
val () = pervasive_load (PATSHOME, "prelude/SATS/memory.sats")
val () = pervasive_load (PATSHOME, "prelude/SATS/string.sats")
val () = pervasive_load (PATSHOME, "prelude/SATS/strptr.sats")
val () = pervasive_load (PATSHOME, "prelude/SATS/tuple.sats")
....

So patsopt automatically load these by default.

Brandon Barker

unread,
Jan 24, 2014, 12:38:24 AM1/24/14
to gmhwxi, ats-lan...@googlegroups.com
I guess that makes sense: we are not assuming assuming a viewtype in this cast: 
cptr2ptr {a:vt0p}{l:addr} (p: cptr (a, l)):<> ptr (l)




Brandon Barker
brandon...@gmail.com


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.

H Zhang

unread,
Jan 24, 2014, 12:40:18 AM1/24/14
to ats-lan...@googlegroups.com
Ah, now I see. I was briefly excited thinking that we could put a boxed type constructor directly onto a C function call :-(

gmhwxi

unread,
Jan 24, 2014, 12:49:49 AM1/24/14
to ats-lan...@googlegroups.com
But what does that buy you?

Brandon Barker

unread,
Jan 24, 2014, 12:55:35 AM1/24/14
to gmhwxi, ats-lan...@googlegroups.com
I was really having similar thoughts earlier today, except I was thinking of entire data(v)types, not just a single constructor. Though I haven't tried it, i guess it is better to avoid having to constantly and unnecessarily work with constructors and pattern matching at the user level, and just stick with a few simple pointer casts at the lower level.

Brandon Barker
brandon...@gmail.com


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.

gmhwxi

unread,
Jan 24, 2014, 1:27:17 AM1/24/14
to ats-lan...@googlegroups.com, gmhwxi
Dataviewtypes are good stuff.

When there are proofs of views involved, casting is tricky. I actually had a bug due to casting that forced me to read source code of cairo. In general, I use casting lightly unless I expect my code to be thoroughly tested.

gmhwxi

unread,
Jan 24, 2014, 1:29:10 AM1/24/14
to ats-lan...@googlegroups.com, gmhwxi
I had the bug this morning (:
Reply all
Reply to author
Forward
0 new messages